Skip to content

HTTPS

[Estable: 2 - Estable]

Estable: 2 Estabilidad: 2 - Estable

Código fuente: lib/https.js

HTTPS es el protocolo HTTP sobre TLS/SSL. En Node.js, esto se implementa como un módulo separado.

Determinar si el soporte de crypto no está disponible

Es posible que Node.js se construya sin incluir soporte para el módulo node:crypto. En tales casos, intentar import desde https o llamar a require('node:https') resultará en un error.

Cuando se usa CommonJS, el error lanzado se puede capturar usando try/catch:

js
let https
try {
  https = require('node:https')
} catch (err) {
  console.error('¡El soporte de https está deshabilitado!')
}

Cuando se usa la palabra clave léxica ESM import, el error solo se puede capturar si se registra un controlador para process.on('uncaughtException') antes de que se realice cualquier intento de cargar el módulo (usando, por ejemplo, un módulo de precarga).

Cuando se usa ESM, si existe la posibilidad de que el código se ejecute en una compilación de Node.js donde el soporte de crypto no esté habilitado, considere usar la función import() en lugar de la palabra clave léxica import:

js
let https
try {
  https = await import('node:https')
} catch (err) {
  console.error('¡El soporte de https está deshabilitado!')
}

Clase: https.Agent

[Historial]

VersiónCambios
v5.3.0Soporte para 0 maxCachedSessions para deshabilitar el almacenamiento en caché de sesiones TLS.
v2.5.0Se agregó el parámetro maxCachedSessions a options para la reutilización de sesiones TLS.
v0.4.5Agregado en: v0.4.5

Un objeto Agent para HTTPS similar a http.Agent. Consulte https.request() para obtener más información.

new Agent([options])

[Historial]

VersiónCambios
v12.5.0No establece automáticamente el nombre del servidor si el host de destino se especificó mediante una dirección IP.
  • options <Object> Conjunto de opciones configurables para establecer en el agente. Puede tener los mismos campos que para http.Agent(options), y
    • maxCachedSessions <number> número máximo de sesiones TLS almacenadas en caché. Use 0 para deshabilitar el almacenamiento en caché de sesiones TLS. Predeterminado: 100.
    • servername <string> el valor de la extensión de Indicación de Nombre de Servidor que se enviará al servidor. Use una cadena vacía '' para deshabilitar el envío de la extensión. Predeterminado: nombre de host del servidor de destino, a menos que el servidor de destino se especifique mediante una dirección IP, en cuyo caso el valor predeterminado es '' (sin extensión). Consulte Reanudación de Sesión para obtener información sobre la reutilización de sesiones TLS.

Evento: 'keylog'

Agregado en: v13.2.0, v12.16.0

  • line <Buffer> Línea de texto ASCII, en formato NSS SSLKEYLOGFILE.
  • tlsSocket <tls.TLSSocket> La instancia tls.TLSSocket en la que se generó.

El evento keylog se emite cuando un material de clave es generado o recibido por una conexión gestionada por este agente (normalmente antes de que se complete el handshake, pero no necesariamente). Este material de clave se puede almacenar para depuración, ya que permite descifrar el tráfico TLS capturado. Se puede emitir varias veces para cada socket.

Un caso de uso típico es añadir las líneas recibidas a un archivo de texto común, que luego es utilizado por un software (como Wireshark) para descifrar el tráfico:

js
// ...
https.globalAgent.on('keylog', (line, tlsSocket) => {
  fs.appendFileSync('/tmp/ssl-keys.log', line, { mode: 0o600 })
})

Clase: https.Server

Agregado en: v0.3.4

Ver http.Server para más información.

server.close([callback])

Agregado en: v0.1.90

Ver server.close() en el módulo node:http.

server[Symbol.asyncDispose]()

Agregado en: v20.4.0

[Estable: 1 - Experimental]

Estable: 1 Estabilidad: 1 - Experimental

Llama a server.close() y devuelve una promesa que se cumple cuando el servidor se ha cerrado.

server.closeAllConnections()

Agregado en: v18.2.0

Ver server.closeAllConnections() en el módulo node:http.

server.closeIdleConnections()

Agregado en: v18.2.0

Ver server.closeIdleConnections() en el módulo node:http.

server.headersTimeout

Agregado en: v11.3.0

Ver server.headersTimeout en el módulo node:http.

server.listen()

Comienza el servidor HTTPS a escuchar conexiones encriptadas. Este método es idéntico a server.listen() de net.Server.

server.maxHeadersCount

Ver server.maxHeadersCount en el módulo node:http.

server.requestTimeout

[Historial]

VersiónCambios
v18.0.0El tiempo de espera predeterminado de la solicitud cambió de sin tiempo de espera a 300 segundos (5 minutos).
v14.11.0Añadido en: v14.11.0

Ver server.requestTimeout en el módulo node:http.

server.setTimeout([msecs][, callback])

Añadido en: v0.11.2

Ver server.setTimeout() en el módulo node:http.

server.timeout

[Historial]

VersiónCambios
v13.0.0El tiempo de espera predeterminado cambió de 120s a 0 (sin tiempo de espera).
v0.11.2Agregado en: v0.11.2
  • <number> Predeterminado: 0 (sin tiempo de espera)

Ver server.timeout en el módulo node:http.

server.keepAliveTimeout

Agregado en: v8.0.0

  • <number> Predeterminado: 5000 (5 segundos)

Ver server.keepAliveTimeout en el módulo node:http.

https.createServer([options][, requestListener])

Agregado en: v0.3.4

js
// curl -k https://localhost:8000/
import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem'),
}

createServer(options, (req, res) => {
  res.writeHead(200)
  res.end('hello world\n')
}).listen(8000)
js
// curl -k https://localhost:8000/
const https = require('node:https')
const fs = require('node:fs')

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
}

https
  .createServer(options, (req, res) => {
    res.writeHead(200)
    res.end('hello world\n')
  })
  .listen(8000)

O

js
import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'

const options = {
  pfx: readFileSync('test_cert.pfx'),
  passphrase: 'sample',
}

createServer(options, (req, res) => {
  res.writeHead(200)
  res.end('hello world\n')
}).listen(8000)
js
const https = require('node:https')
const fs = require('node:fs')

const options = {
  pfx: fs.readFileSync('test_cert.pfx'),
  passphrase: 'sample',
}

https
  .createServer(options, (req, res) => {
    res.writeHead(200)
    res.end('hello world\n')
  })
  .listen(8000)

Para generar el certificado y la clave para este ejemplo, ejecute:

bash
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
  -keyout private-key.pem -out certificate.pem

Luego, para generar el certificado pfx para este ejemplo, ejecute:

bash
openssl pkcs12 -certpbe AES-256-CBC -export -out test_cert.pfx \
  -inkey private-key.pem -in certificate.pem -passout pass:sample

https.get(options[, callback])

https.get(url[, options][, callback])

[Historial]

VersiónCambios
v10.9.0El parámetro url ahora se puede pasar junto con un objeto options separado.
v7.5.0El parámetro options puede ser un objeto WHATWG URL.
v0.3.6Añadido en: v0.3.6

Similar a http.get() pero para HTTPS.

options puede ser un objeto, una cadena o un objeto URL. Si options es una cadena, se analiza automáticamente con new URL(). Si es un objeto URL, se convertirá automáticamente en un objeto options ordinario.

js
import { get } from 'node:https'
import process from 'node:process'

get('https://encrypted.google.com/', res => {
  console.log('statusCode:', res.statusCode)
  console.log('headers:', res.headers)

  res.on('data', d => {
    process.stdout.write(d)
  })
}).on('error', e => {
  console.error(e)
})
js
const https = require('node:https')

https
  .get('https://encrypted.google.com/', res => {
    console.log('statusCode:', res.statusCode)
    console.log('headers:', res.headers)

    res.on('data', d => {
      process.stdout.write(d)
    })
  })
  .on('error', e => {
    console.error(e)
  })

https.globalAgent

[Historial]

VersiónCambios
v19.0.0El agente ahora utiliza HTTP Keep-Alive y un tiempo de espera de 5 segundos por defecto.
v0.5.9Añadido en: v0.5.9

Instancia global de https.Agent para todas las solicitudes de cliente HTTPS. Difiere de una configuración predeterminada de https.Agent al tener keepAlive habilitado y un timeout de 5 segundos.

https.request(options[, callback])

https.request(url[, options][, callback])

[Historial]

VersiónCambios
v22.4.0, v20.16.0La opción clientCertEngine depende del soporte del motor personalizado en OpenSSL que está en desuso en OpenSSL 3.
v16.7.0, v14.18.0Al usar un objeto URL, el nombre de usuario y la contraseña analizados ahora se decodificarán URI correctamente.
v14.1.0, v13.14.0Ahora se acepta la opción highWaterMark.
v10.9.0El parámetro url ahora se puede pasar junto con un objeto options separado.
v9.3.0El parámetro options ahora puede incluir clientCertEngine.
v7.5.0El parámetro options puede ser un objeto URL WHATWG.
v0.3.6Añadido en: v0.3.6

Realiza una solicitud a un servidor web seguro.

También se aceptan las siguientes options adicionales de tls.connect(): ca, cert, ciphers, clientCertEngine (obsoleto), crl, dhparam, ecdhCurve, honorCipherOrder, key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext, highWaterMark.

options puede ser un objeto, una cadena o un objeto URL. Si options es una cadena, se analiza automáticamente con new URL(). Si es un objeto URL, se convertirá automáticamente en un objeto options ordinario.

https.request() devuelve una instancia de la clase http.ClientRequest. La instancia ClientRequest es un flujo grabable. Si se necesita cargar un archivo con una solicitud POST, entonces escribir en el objeto ClientRequest.

js
import { request } from 'node:https'
import process from 'node:process'

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
}

const req = request(options, res => {
  console.log('statusCode:', res.statusCode)
  console.log('headers:', res.headers)

  res.on('data', d => {
    process.stdout.write(d)
  })
})

req.on('error', e => {
  console.error(e)
})
req.end()
js
const https = require('node:https')

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
}

const req = https.request(options, res => {
  console.log('statusCode:', res.statusCode)
  console.log('headers:', res.headers)

  res.on('data', d => {
    process.stdout.write(d)
  })
})

req.on('error', e => {
  console.error(e)
})
req.end()

Ejemplo usando opciones de tls.connect():

js
const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
}
options.agent = new https.Agent(options)

const req = https.request(options, res => {
  // ...
})

Alternativamente, optar por no utilizar la agrupación de conexiones al no usar un Agent.

js
const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  agent: false,
}

const req = https.request(options, res => {
  // ...
})

Ejemplo usando una URL como options:

js
const options = new URL('https://abc:')

const req = https.request(options, res => {
  // ...
})

Ejemplo de fijación en la huella digital del certificado, o la clave pública (similar a pin-sha256):

js
import { checkServerIdentity } from 'node:tls'
import { Agent, request } from 'node:https'
import { createHash } from 'node:crypto'

function sha256(s) {
  return createHash('sha256').update(s).digest('base64')
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function (host, cert) {
    // Asegurarse de que el certificado se emita al host al que estamos conectados
    const err = checkServerIdentity(host, cert)
    if (err) {
      return err
    }

    // Fijar la clave pública, similar a la fijación HPKP pin-sha256
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8='
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg =
        'Error de verificación del certificado: ' +
        `La clave pública de '${cert.subject.CN}' ` +
        'no coincide con nuestra huella digital fijada'
      return new Error(msg)
    }

    // Fijar el certificado exacto, en lugar de la clave pública
    const cert256 =
      'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' + '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65'
    if (cert.fingerprint256 !== cert256) {
      const msg =
        'Error de verificación del certificado: ' +
        `El certificado de '${cert.subject.CN}' ` +
        'no coincide con nuestra huella digital fijada'
      return new Error(msg)
    }

    // Este bucle es solo informativo.
    // Imprimir el certificado y las huellas digitales de la clave pública de todos los certificados en la
    // cadena. Es común fijar la clave pública del emisor en la pública
    // Internet, mientras se fija la clave pública del servicio en sensible
    // entornos.
    let lastprint256
    do {
      console.log('Nombre común del sujeto:', cert.subject.CN)
      console.log('  Huella digital SHA256 del certificado:', cert.fingerprint256)

      const hash = createHash('sha256')
      console.log('  Ping-sha256 de clave pública:', sha256(cert.pubkey))

      lastprint256 = cert.fingerprint256
      cert = cert.issuerCertificate
    } while (cert.fingerprint256 !== lastprint256)
  },
}

options.agent = new Agent(options)
const req = request(options, res => {
  console.log('Todo OK. El servidor coincidió con nuestro certificado fijado o clave pública')
  console.log('statusCode:', res.statusCode)

  res.on('data', d => {})
})

req.on('error', e => {
  console.error(e.message)
})
req.end()
js
const tls = require('node:tls')
const https = require('node:https')
const crypto = require('node:crypto')

function sha256(s) {
  return crypto.createHash('sha256').update(s).digest('base64')
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function (host, cert) {
    // Asegurarse de que el certificado se emita al host al que estamos conectados
    const err = tls.checkServerIdentity(host, cert)
    if (err) {
      return err
    }

    // Fijar la clave pública, similar a la fijación HPKP pin-sha256
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8='
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg =
        'Error de verificación del certificado: ' +
        `La clave pública de '${cert.subject.CN}' ` +
        'no coincide con nuestra huella digital fijada'
      return new Error(msg)
    }

    // Fijar el certificado exacto, en lugar de la clave pública
    const cert256 =
      'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' + '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65'
    if (cert.fingerprint256 !== cert256) {
      const msg =
        'Error de verificación del certificado: ' +
        `El certificado de '${cert.subject.CN}' ` +
        'no coincide con nuestra huella digital fijada'
      return new Error(msg)
    }

    // Este bucle es solo informativo.
    // Imprimir el certificado y las huellas digitales de la clave pública de todos los certificados en la
    // cadena. Es común fijar la clave pública del emisor en la pública
    // Internet, mientras se fija la clave pública del servicio en sensible
    // entornos.
    do {
      console.log('Nombre común del sujeto:', cert.subject.CN)
      console.log('  Huella digital SHA256 del certificado:', cert.fingerprint256)

      hash = crypto.createHash('sha256')
      console.log('  Ping-sha256 de clave pública:', sha256(cert.pubkey))

      lastprint256 = cert.fingerprint256
      cert = cert.issuerCertificate
    } while (cert.fingerprint256 !== lastprint256)
  },
}

options.agent = new https.Agent(options)
const req = https.request(options, res => {
  console.log('Todo OK. El servidor coincidió con nuestro certificado fijado o clave pública')
  console.log('statusCode:', res.statusCode)

  res.on('data', d => {})
})

req.on('error', e => {
  console.error(e.message)
})
req.end()

Salidas por ejemplo:

text
Nombre común del sujeto: github.com
  Huella digital SHA256 del certificado: FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65
  Ping-sha256 de clave pública: SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=
Nombre común del sujeto: Sectigo ECC Domain Validation Secure Server CA
  Huella digital SHA256 del certificado: 61:E9:73:75:E9:F6:DA:98:2F:F5:C1:9E:2F:94:E6:6C:4E:35:B6:83:7C:E3:B9:14:D2:24:5C:7F:5F:65:82:5F
  Ping-sha256 de clave pública: Eep0p/AsSa9lFUH6KT2UY+9s1Z8v7voAPkQ4fGknZ2g=
Nombre común del sujeto: USERTrust ECC Certification Authority
  Huella digital SHA256 del certificado: A6:CF:64:DB:B4:C8:D5:FD:19:CE:48:89:60:68:DB:03:B5:33:A8:D1:33:6C:62:56:A8:7D:00:CB:B3:DE:F3:EA
  Ping-sha256 de clave pública: UJM2FOhG9aTNY0Pg4hgqjNzZ/lQBiMGRxPD5Y2/e0bw=
Nombre común del sujeto: AAA Certificate Services
  Huella digital SHA256 del certificado: D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4
  Ping-sha256 de clave pública: vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=
Todo OK. El servidor coincidió con nuestro certificado fijado o clave pública
statusCode: 200