TLS (SSL)#

稳定性:2 - 稳定

源代码: lib/tls.js

node:tls 模块提供了在 OpenSSL 之上构建的传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的实现。可以使用以下方法访问该模块

const tls = require('node:tls'); 

确定是否不支持加密#

Node.js 可以在不包含对 node:crypto 模块的支持的情况下构建。在这种情况下,尝试从 tlsimport 或调用 require('node:tls') 将导致抛出错误。

使用 CommonJS 时,可以使用 try/catch 捕获抛出的错误

let tls;
try {
  tls = require('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
} 

使用词法 ESM import 关键字时,只有在尝试加载模块之前注册 process.on('uncaughtException') 的处理程序(例如,使用预加载模块)时才能捕获错误。

使用 ESM 时,如果代码有可能在未启用加密支持的 Node.js 构建上运行,请考虑使用 import() 函数,而不是词法 import 关键字

let tls;
try {
  tls = await import('node:tls');
} catch (err) {
  console.error('tls support is disabled!');
} 

TLS/SSL 概念#

TLS/SSL 是依赖于公钥基础设施 (PKI) 的一组协议,用于在客户端和服务器之间实现安全通信。对于大多数常见情况,每个服务器都必须具有一个私钥。

私钥可以通过多种方式生成。以下示例说明了如何使用 OpenSSL 命令行界面生成 2048 位 RSA 私钥

openssl genrsa -out ryans-key.pem 2048 

使用 TLS/SSL,所有服务器(和某些客户端)都必须具有一个证书。证书是与私钥相对应的公钥,并且由证书颁发机构或私钥的所有者进行数字签名(此类证书称为“自签名”)。获取证书的第一步是创建证书签名请求 (CSR) 文件。

OpenSSL 命令行界面可用于为私钥生成 CSR

openssl req -new -sha256 -key ryans-key.pem -out ryans-csr.pem 

生成 CSR 文件后,可以将其发送给证书颁发机构进行签名,或用于生成自签名证书。

以下示例说明了如何使用 OpenSSL 命令行界面创建自签名证书

openssl x509 -req -in ryans-csr.pem -signkey ryans-key.pem -out ryans-cert.pem 

生成证书后,可以使用它生成 .pfx.p12 文件

openssl pkcs12 -export -in ryans-cert.pem -inkey ryans-key.pem \
      -certfile ca-cert.pem -out ryans.pfx 

其中

  • in:是已签名的证书
  • inkey:是关联的私钥
  • certfile:是将所有证书颁发机构 (CA) 证书连接到一个文件中的连接,例如 cat ca1-cert.pem ca2-cert.pem > ca-cert.pem

完美前向保密#

术语前向保密完美前向保密描述了密钥协商(即密钥交换)方法的一个特性。也就是说,服务器和客户端密钥用于协商新的临时密钥,这些密钥专门且仅用于当前通信会话。实际上,这意味着即使服务器的私钥遭到破坏,只有当攻击者设法获得专门为该会话生成的密钥对时,窃听者才能解密通信。

通过在每次 TLS/SSL 握手时随机生成密钥对来实现密钥协商(与对所有会话使用同一密钥相反)。实现此技术的办法称为“临时”。

目前,通常使用两种方法来实现完美前向保密(注意传统缩写中追加的字符“E”)

  • ECDHE:椭圆曲线 Diffie-Hellman 密钥协商协议的临时版本。
  • DHE:Diffie-Hellman 密钥协商协议的临时版本。

默认情况下启用使用 ECDHE 的完美前向保密。在创建 TLS 服务器时可以使用 ecdhCurve 选项来定制要使用的受支持 ECDH 曲线列表。有关更多信息,请参阅 tls.createServer()

默认情况下禁用 DHE,但可以通过将 dhparam 选项设置为 'auto' 来启用它和 ECDHE。还支持自定义 DHE 参数,但建议使用自动选择的众所周知参数。

在 TLSv1.2 之前,完美前向保密是可选的。从 TLSv1.3 开始,始终使用 (EC)DHE(PSK 专用连接除外)。

ALPN 和 SNI#

ALPN(应用程序层协议协商扩展)和 SNI(服务器名称指示)是 TLS 握手扩展

  • ALPN:允许将一个 TLS 服务器用于多个协议(HTTP、HTTP/2)
  • SNI:允许将一个 TLS 服务器用于具有不同证书的多个主机名。

预共享密钥#

TLS-PSK 支持可用作基于证书的正常身份验证的替代方案。它使用预共享密钥而不是证书来验证 TLS 连接,从而提供相互身份验证。TLS-PSK 和公钥基础设施并非相互排斥。客户端和服务器可以同时容纳两者,并在正常的密码协商步骤中选择其中任何一个。

只有在存在安全地与每台连接机器共享密钥的方法时,TLS-PSK 才是一种不错的选择,因此它不会取代大多数 TLS 用途的公钥基础设施 (PKI)。近年来,OpenSSL 中的 TLS-PSK 实施出现了许多安全漏洞,主要是因为它仅被少数应用程序使用。在切换到 PSK 密码之前,请考虑所有替代解决方案。在生成 PSK 时,至关重要的是使用足够的熵,如 RFC 4086 中所述。从密码或其他低熵源派生共享密钥是不安全的。

默认情况下禁用 PSK 密码,因此使用 TLS-PSK 需要使用 ciphers 选项明确指定密码套件。可以通过 openssl ciphers -v 'PSK' 检索可用密码列表。所有 TLS 1.3 密码都符合 PSK 的条件,并且可以通过 openssl ciphers -v -s -tls1_3 -psk 检索。

根据 RFC 4279,必须支持长度最长为 128 字节的 PSK 标识和长度最长为 64 字节的 PSK。从 OpenSSL 1.1.0 开始,最大标识大小为 128 字节,最大 PSK 长度为 256 字节。

由于底层 OpenSSL API 的限制,当前实现不支持异步 PSK 回调。

客户端发起的重新协商攻击缓解#

TLS 协议允许客户端重新协商 TLS 会话的某些方面。不幸的是,会话重新协商需要不成比例的服务器端资源,使其成为拒绝服务攻击的潜在媒介。

为了降低风险,每十分钟重新协商的次数限制为三次。当超过此阈值时,tls.TLSSocket 实例上会发出 'error' 事件。这些限制是可配置的

  • tls.CLIENT_RENEG_LIMIT <number> 指定重新协商请求的次数。默认值:3
  • tls.CLIENT_RENEG_WINDOW <number> 以秒为单位指定重新协商窗口。默认值:600(10 分钟)。

在没有充分理解含义和风险的情况下,不应修改默认重新协商限制。

TLSv1.3 不支持重新协商。

会话恢复#

建立 TLS 会话可能相对较慢。可以通过保存并稍后重用会话状态来加速此过程。有几种机制可以做到这一点,此处从最旧到最新(也是首选)进行讨论。

会话标识符#

服务器为新连接生成唯一 ID 并将其发送给客户端。客户端和服务器保存会话状态。重新连接时,客户端会发送其已保存会话状态的 ID,如果服务器也具有该 ID 的状态,则它可以同意使用它。否则,服务器将创建一个新会话。有关更多信息,请参阅 RFC 2246,第 23 和 30 页。

大多数 Web 浏览器在进行 HTTPS 请求时都支持使用会话标识符恢复会话。

对于 Node.js,客户端等待 'session' 事件以获取会话数据,并向后续 tls.connect()session 选项提供数据以重用会话。服务器必须为 'newSession''resumeSession' 事件实现处理程序,以使用会话 ID 作为查找键保存和恢复会话数据以重用会话。要跨负载均衡器或集群工作进程重用会话,服务器必须在其会话处理程序中使用共享会话缓存(例如 Redis)。

会话票证#

服务器加密整个会话状态,并将其作为“票证”发送给客户端。重新连接时,该状态在初始连接中发送到服务器。此机制避免了对服务器端会话缓存的需求。如果服务器出于任何原因(无法解密、太旧等)不使用票证,它将创建一个新会话并发送一个新票证。有关更多信息,请参阅 RFC 5077

许多 Web 浏览器在进行 HTTPS 请求时开始普遍支持使用会话票证恢复会话。

对于 Node.js,客户端使用与使用会话标识符恢复会话相同的 API 来使用会话票证恢复会话。用于调试,如果 tls.TLSSocket.getTLSTicket() 返回一个值,则会话数据包含一个票证,否则它包含客户端会话状态。

对于 TLSv1.3,请注意服务器可能会发送多个票证,从而导致多个 'session' 事件,有关更多信息,请参阅 'session'

单进程服务器无需任何特定实现即可使用会话票证。要跨服务器重启或负载均衡器使用会话票证,所有服务器都必须具有相同的票证密钥。内部有三个 16 字节密钥,但 tls API 将它们公开为一个 48 字节缓冲区以方便使用。

可以通过在一个服务器实例上调用 server.getTicketKeys() 来获取票证密钥,然后分发它们,但更合理的做法是安全地生成 48 字节的安全随机数据,并使用 tls.createServer()ticketKeys 选项设置它们。应定期重新生成密钥,并且可以使用 server.setTicketKeys() 重置服务器的密钥。

会话票证密钥是加密密钥,它们必须安全地存储。对于 TLS 1.2 及更低版本,如果它们受到损害,则使用它们加密的票证的所有会话都可以被解密。它们不应存储在磁盘上,并且应定期重新生成。

如果客户端宣告支持票证,服务器将发送它们。服务器可以通过在 secureOptions 中提供 require('node:constants').SSL_OP_NO_TICKET 来禁用票证。

会话标识符和会话票证都会超时,导致服务器创建新的会话。超时可以通过 tls.createServer()sessionTimeout 选项进行配置。

对于所有机制,当恢复失败时,服务器将创建新的会话。由于未能恢复会话不会导致 TLS/HTTPS 连接失败,因此很容易忽略不必要的糟糕 TLS 性能。OpenSSL CLI 可用于验证服务器是否正在恢复会话。例如,使用 -reconnect 选项到 openssl s_client

openssl s_client -connect localhost:443 -reconnect 

通读调试输出。例如,第一个连接应显示“New”

New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 

例如,后续连接应显示“Reused”

Reused, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 

修改默认 TLS 密码套件#

Node.js 使用一组默认启用的和禁用的 TLS 密码构建。在构建 Node.js 时可以配置此默认密码列表,以允许发行版提供它们自己的默认列表。

可以使用以下命令显示默认密码套件

node -p crypto.constants.defaultCoreCipherList | tr ':' '\n'
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES256-GCM-SHA384
DHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-SHA256
DHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES256-SHA384
ECDHE-RSA-AES256-SHA256
DHE-RSA-AES256-SHA256
HIGH
!aNULL
!eNULL
!EXPORT
!DES
!RC4
!MD5
!PSK
!SRP
!CAMELLIA 

可以使用 --tls-cipher-list 命令行开关(直接或通过 NODE_OPTIONS 环境变量)完全替换此默认值。例如,以下内容将 ECDHE-RSA-AES128-GCM-SHA256:!RC4 设置为默认 TLS 密码套件

node --tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4' server.js

export NODE_OPTIONS=--tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4'
node server.js 

要验证,请使用以下命令显示设置的密码列表,注意 defaultCoreCipherListdefaultCipherList 之间的区别

node --tls-cipher-list='ECDHE-RSA-AES128-GCM-SHA256:!RC4' -p crypto.constants.defaultCipherList | tr ':' '\n'
ECDHE-RSA-AES128-GCM-SHA256
!RC4 

defaultCoreCipherList 列表在编译时设置,而 defaultCipherList 在运行时设置。

要从运行时修改默认密码套件,请修改 tls.DEFAULT_CIPHERS 变量,这必须在监听任何套接字之前执行,它不会影响已打开的套接字。例如

// Remove Obsolete CBC Ciphers and RSA Key Exchange based Ciphers as they don't provide Forward Secrecy
tls.DEFAULT_CIPHERS +=
  ':!ECDHE-RSA-AES128-SHA:!ECDHE-RSA-AES128-SHA256:!ECDHE-RSA-AES256-SHA:!ECDHE-RSA-AES256-SHA384' +
  ':!ECDHE-ECDSA-AES128-SHA:!ECDHE-ECDSA-AES128-SHA256:!ECDHE-ECDSA-AES256-SHA:!ECDHE-ECDSA-AES256-SHA384' +
  ':!kRSA'; 

还可以使用 tls.createSecureContext() 中的 ciphers 选项在每个客户端或服务器基础上替换默认值,该选项在 tls.createServer()tls.connect() 中也可用,以及在创建新的 tls.TLSSocket 时使用。

密码列表可以包含 TLSv1.3 密码套件名称(以 'TLS_' 开头的名称)和 TLSv1.2 及更低版本的密码套件规范的混合。TLSv1.2 密码支持旧版规范格式,有关详细信息,请参阅 OpenSSL 密码列表格式 文档,但这些规范适用于 TLSv1.3 密码。TLSv1.3 套件只能通过在密码列表中包含其全名来启用。例如,无法使用旧版 TLSv1.2 'EECDH''!EECDH' 规范来启用或禁用它们。

尽管 TLSv1.3 和 TLSv1.2 密码套件的相对顺序不同,但 TLSv1.3 协议比 TLSv1.2 安全得多,如果握手表明支持 TLSv1.3 且启用了任何 TLSv1.3 密码套件,则始终会选择 TLSv1.3。

Node.js 中包含的默认密码套件经过精心挑选,以反映当前的安全最佳实践和风险缓解措施。更改默认密码套件会对应用程序的安全性产生重大影响。仅在绝对必要时才应使用 --tls-cipher-list 开关和 ciphers 选项。

默认密码套件首选适用于 Chrome 的“现代密码”设置 的 GCM 密码,还首选 ECDHE 和 DHE 密码以实现完美前向保密,同时提供一些向后兼容性。

依赖于不安全且已弃用的基于 RC4 或 DES 的密码(如 Internet Explorer 6)的旧客户端无法使用默认配置完成握手过程。如果必须支持这些客户端,则 TLS 建议 可能会提供兼容的密码套件。有关格式的更多详细信息,请参阅 OpenSSL 密码列表格式 文档。

只有五个 TLSv1.3 密码套件

  • 'TLS_AES_256_GCM_SHA384'
  • 'TLS_CHACHA20_POLY1305_SHA256'
  • 'TLS_AES_128_GCM_SHA256'
  • 'TLS_AES_128_CCM_SHA256'
  • 'TLS_AES_128_CCM_8_SHA256'

默认情况下启用前三个。TLSv1.3 支持这两个基于 CCM 的套件,因为它们在受限系统上可能性能更高,但由于它们提供的安全性较低,因此默认情况下不会启用它们。

X509 证书错误代码#

由于 OpenSSL 报告的证书错误,多个函数可能会失败。在这种情况下,该函数通过其回调提供一个 <Error>,该回调具有属性 code,该属性可以采用以下值之一

  • 'UNABLE_TO_GET_ISSUER_CERT':无法获取颁发者证书。
  • 'UNABLE_TO_GET_CRL':无法获取证书 CRL。
  • 'UNABLE_TO_DECRYPT_CERT_SIGNATURE':无法解密证书签名。
  • 'UNABLE_TO_DECRYPT_CRL_SIGNATURE':无法解密 CRL 签名。
  • 'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY':无法解码颁发者公钥。
  • 'CERT_SIGNATURE_FAILURE':证书签名失败。
  • 'CRL_SIGNATURE_FAILURE':CRL 签名失败。
  • 'CERT_NOT_YET_VALID':证书尚未有效。
  • 'CERT_HAS_EXPIRED':证书已过期。
  • 'CRL_NOT_YET_VALID':CRL 尚未有效。
  • 'CRL_HAS_EXPIRED':CRL 已过期。
  • 'ERROR_IN_CERT_NOT_BEFORE_FIELD':证书的 notBefore 字段格式错误。
  • 'ERROR_IN_CERT_NOT_AFTER_FIELD':证书的 notAfter 字段格式错误。
  • 'ERROR_IN_CRL_LAST_UPDATE_FIELD':CRL 的 lastUpdate 字段格式错误。
  • 'ERROR_IN_CRL_NEXT_UPDATE_FIELD':CRL 的 nextUpdate 字段格式错误。
  • 'OUT_OF_MEM':内存不足。
  • 'DEPTH_ZERO_SELF_SIGNED_CERT':自签名证书。
  • 'SELF_SIGNED_CERT_IN_CHAIN':证书链中存在自签名证书。
  • 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY':无法获取本地颁发者证书。
  • 'UNABLE_TO_VERIFY_LEAF_SIGNATURE':无法验证第一个证书。
  • 'CERT_CHAIN_TOO_LONG':证书链过长。
  • 'CERT_REVOKED':证书已吊销。
  • 'INVALID_CA':CA 证书无效。
  • 'PATH_LENGTH_EXCEEDED':路径长度限制已超过。
  • 'INVALID_PURPOSE':不受支持的证书用途。
  • 'CERT_UNTRUSTED':证书不受信任。
  • 'CERT_REJECTED':证书被拒绝。
  • 'HOSTNAME_MISMATCH':主机名不匹配。

类:tls.CryptoStream#

稳定性:0 - 已弃用:改用 tls.TLSSocket

tls.CryptoStream 类表示加密数据流。此类已弃用,不应再使用。

cryptoStream.bytesWritten#

cryptoStream.bytesWritten 属性返回写入底层套接字的总字节数,包括 TLS 协议实现所需的字节数。

类:tls.SecurePair#

稳定性:0 - 已弃用:改用 tls.TLSSocket

tls.createSecurePair() 返回。

事件:'secure'#

一旦建立安全连接,SecurePair 对象就会发出 'secure' 事件。

与检查服务器 'secureConnection' 事件类似,应检查 pair.cleartext.authorized 以确认所使用的证书是否经过适当授权。

类:tls.Server#

使用 TLS 或 SSL 接受加密连接。

事件:'connection'#

在 TLS 握手开始之前,当建立新的 TCP 流时发出此事件。socket 通常是 net.Socket 类型的对象,但与从 net.Server 'connection' 事件创建的套接字不同,它不会接收事件。通常,用户不会希望访问此事件。

此事件也可以由用户显式发出,以将连接注入 TLS 服务器。在这种情况下,可以传递任何 Duplex 流。

事件:'keylog'#

  • line <Buffer> ASCII 文本行,采用 NSS SSLKEYLOGFILE 格式。
  • tlsSocket <tls.TLSSocket> 生成它的 tls.TLSSocket 实例。

当密钥材料由连接生成或接收时,将发出 keylog 事件(通常在握手完成之前,但并非必然如此)。此密钥材料可以存储用于调试,因为它允许解密捕获的 TLS 流量。对于每个套接字,可能会发出多次事件。

典型的用例是将接收的行追加到一个公共文本文件中,该文件稍后由软件(例如 Wireshark)用于解密流量

const logFile = fs.createWriteStream('/tmp/ssl-keys.log', { flags: 'a' });
// ...
server.on('keylog', (line, tlsSocket) => {
  if (tlsSocket.remoteAddress !== '...')
    return; // Only log keys for a particular IP
  logFile.write(line);
}); 

事件:'newSession'#

在创建新的 TLS 会话时,将发出 'newSession' 事件。这可用于将会话存储在外部存储中。数据应提供给 'resumeSession' 回调。

调用时,侦听器回调将传递三个参数

  • sessionId <Buffer> TLS 会话标识符
  • sessionData <Buffer> TLS 会话数据
  • callback <Function> 一个不带参数的回调函数,必须调用它才能通过安全连接发送或接收数据。

仅当在添加事件侦听器后建立连接时,侦听此事件才会有效果。

事件:'OCSPRequest'#

当客户端发送证书状态请求时,将发出 'OCSPRequest' 事件。调用时,侦听器回调将传递三个参数

  • certificate <Buffer> 服务器证书
  • issuer <Buffer> 发行者的证书
  • callback <Function> 必须调用的回调函数以提供 OCSP 请求的结果。

可以解析服务器的当前证书以获取 OCSP URL 和证书 ID;获取 OCSP 响应后,将调用 callback(null, resp),其中 resp 是包含 OCSP 响应的 Buffer 实例。certificateissuer 都是主证书和发行者证书的 Buffer DER 表示形式。这些可用于获取 OCSP 证书 ID 和 OCSP 端点 URL。

或者,可以调用 callback(null, null),表示没有 OCSP 响应。

调用 callback(err) 将导致 socket.destroy(err) 调用。

OCSP 请求的典型流程如下

  1. 客户端连接到服务器并发送 'OCSPRequest'(通过 ClientHello 中的状态信息扩展)。
  2. 服务器接收请求并发出 'OCSPRequest' 事件,如果已注册,则调用侦听器。
  3. 服务器从 certificateissuer 中提取 OCSP URL,并对 CA 执行 OCSP 请求
  4. 服务器从 CA 接收 'OCSPResponse' 并通过 callback 参数将其发送回客户端
  5. 客户端验证响应并销毁套接字或执行握手。

如果证书是自签名的或颁发者不在根证书列表中,则 issuer 可以为 null。(在建立 TLS 连接时,可以通过 ca 选项提供颁发者。)

仅当在添加事件侦听器后建立连接时,侦听此事件才会有效果。

可以使用 asn1.js 等 npm 模块来解析证书。

事件:'resumeSession'#

当客户端请求恢复先前的 TLS 会话时,会发出 'resumeSession' 事件。调用侦听器回调时会传递两个参数

  • sessionId <Buffer> TLS 会话标识符
  • callback <Function> 当恢复先前的会话时要调用的回调函数:callback([err[, sessionData]])

事件侦听器应在外部存储中查找 'newSession' 事件处理程序使用给定的 sessionId 保存的 sessionData。如果找到,请调用 callback(null, sessionData) 以恢复会话。如果找不到,则无法恢复会话。必须在没有 sessionData 的情况下调用 callback(),以便握手可以继续进行并可以创建新会话。可以调用 callback(err) 来终止传入连接并销毁套接字。

仅当在添加事件侦听器后建立连接时,侦听此事件才会有效果。

以下说明如何恢复 TLS 会话

const tlsSessionStore = {};
server.on('newSession', (id, data, cb) => {
  tlsSessionStore[id.toString('hex')] = data;
  cb();
});
server.on('resumeSession', (id, cb) => {
  cb(null, tlsSessionStore[id.toString('hex')] || null);
}); 

事件:'secureConnection'#

'secureConnection' 事件在成功完成新连接的握手过程后触发。调用侦听器回调时,会传递一个参数

tlsSocket.authorized 属性是一个 boolean,指示客户端是否已通过服务器提供的其中一个证书颁发机构验证。如果 tlsSocket.authorizedfalse,则 socket.authorizationError 设置为描述授权失败的原因。根据 TLS 服务器的设置,仍可能接受未经授权的连接。

tlsSocket.alpnProtocol 属性是一个包含所选 ALPN 协议的字符串。当 ALPN 没有选定的协议,因为客户端或服务器没有发送 ALPN 扩展时,tlsSocket.alpnProtocol 等于 false

tlsSocket.servername 属性是一个包含通过 SNI 请求的服务器名称的字符串。

事件:'tlsClientError'#

'tlsClientError' 事件在建立安全连接之前发生错误时触发。调用侦听器回调时,会传递两个参数

  • exception <Error> 描述错误的 Error 对象
  • tlsSocket <tls.TLSSocket> 发生错误的 tls.TLSSocket 实例。

server.addContext(hostname, context)#

server.addContext() 方法添加了一个安全上下文,如果客户端请求的 SNI 名称与提供的 hostname(或通配符)匹配,则将使用该安全上下文。

当存在多个匹配的上下文时,将使用最近添加的一个。

server.address()#

返回服务器的绑定地址、地址族名称和端口,如操作系统报告的那样。有关更多信息,请参阅 net.Server.address()

server.close([callback])#

  • callback <Function> 将注册一个侦听器回调,以侦听服务器实例的 'close' 事件。
  • 返回:<tls.Server>

server.close() 方法停止服务器接受新连接。

此函数异步操作。当服务器没有更多打开的连接时,将发出 'close' 事件。

server.getTicketKeys()#

  • 返回:<Buffer> 包含会话票证密钥的 48 字节缓冲区。

返回会话票证密钥。

有关更多信息,请参阅 会话恢复

server.listen()#

启动服务器以侦听加密连接。此方法与 server.listen()net.Server 相同。

server.setSecureContext(options)#

server.setSecureContext() 方法替换现有服务器的安全上下文。与服务器的现有连接不会中断。

server.setTicketKeys(keys)#

设置会话票证密钥。

对票证密钥的更改仅对将来的服务器连接有效。现有或当前挂起的服务器连接将使用以前的密钥。

有关更多信息,请参阅 会话恢复

类:tls.TLSSocket#

对写入数据和所有必需的 TLS 协商执行透明加密。

tls.TLSSocket 的实例实现双工 Stream 接口。

返回 TLS 连接元数据的函数(例如 tls.TLSSocket.getPeerCertificate())仅在连接打开时返回数据。

new tls.TLSSocket(socket[, options])#

  • socket <net.Socket> | <stream.Duplex> 在服务器端,任何 Duplex 流。在客户端,任何 net.Socket 实例(对于客户端上的通用 Duplex 流支持,必须使用 tls.connect())。
  • options <Object>
    • enableTrace:请参阅 tls.createServer()
    • isServer:SSL/TLS 协议是不对称的,TLSSockets 必须知道它们是作为服务器还是客户端运行。如果为 true,TLS 套接字将被实例化为服务器。默认:false
    • server <net.Server> 一个 net.Server 实例。
    • requestCert:是否通过请求证书对远程对等方进行身份验证。客户端始终请求服务器证书。服务器(isServer 为 true)可以将 requestCert 设置为 true 以请求客户端证书。
    • rejectUnauthorized:请参阅 tls.createServer()
    • ALPNProtocols:请参阅 tls.createServer()
    • SNICallback:请参阅 tls.createServer()
    • session <Buffer> 一个包含 TLS 会话的 Buffer 实例。
    • requestOCSP <boolean> 如果为 true,则指定将 OCSP 状态请求扩展添加到客户端 hello 中,并在建立安全通信之前在套接字上发出 'OCSPResponse' 事件
    • secureContext:使用 tls.createSecureContext() 创建的 TLS 上下文对象。如果 提供 secureContext,则将通过将整个 options 对象传递给 tls.createSecureContext() 来创建一个
    • ...: tls.createSecureContext() 选项,在 secureContext 选项缺失时使用。否则,将忽略这些选项。

从现有 TCP 套接字构建新的 tls.TLSSocket 对象。

事件:'keylog'#

  • line <Buffer> ASCII 文本行,采用 NSS SSLKEYLOGFILE 格式。

当套接字生成或接收密钥材料时,将在 tls.TLSSocket 上发出 keylog 事件。此密钥材料可以存储用于调试,因为它允许解密捕获的 TLS 流量。它可能会在握手完成之前或之后多次发出。

典型的用例是将接收的行追加到一个公共文本文件中,该文件稍后由软件(例如 Wireshark)用于解密流量

const logFile = fs.createWriteStream('/tmp/ssl-keys.log', { flags: 'a' });
// ...
tlsSocket.on('keylog', (line) => logFile.write(line)); 

事件:'OCSPResponse'#

如果在创建 tls.TLSSocket 时设置了 requestOCSP 选项,并且已收到 OCSP 响应,则将发出 'OCSPResponse' 事件。调用时,将向侦听器回调传递单个参数

  • response <Buffer> 服务器的 OCSP 响应

通常,response 是来自服务器 CA 的数字签名对象,其中包含有关服务器证书吊销状态的信息。

事件:'secureConnect'#

在新连接的握手过程成功完成后,将发出 'secureConnect' 事件。无论服务器证书是否已授权,都将调用侦听器回调。客户端负责检查 tlsSocket.authorized 属性以确定服务器证书是否由指定的 CA 之一签名。如果 tlsSocket.authorized === false,则可以通过检查 tlsSocket.authorizationError 属性来找到错误。如果使用了 ALPN,则可以检查 tlsSocket.alpnProtocol 属性以确定协商的协议。

当使用 new tls.TLSSocket() 构造函数创建 <tls.TLSSocket> 时,不会发出 'secureConnect' 事件。

事件:'session'#

当新的会话或 TLS 票证可用时,'session' 事件会在客户端 tls.TLSSocket 上发出。这可能在握手完成之前或之后,具体取决于已协商的 TLS 协议版本。该事件不会在服务器上发出,或者如果未创建新会话,例如,在恢复连接时。对于某些 TLS 协议版本,该事件可能会发出多次,在这种情况下,所有会话都可以用于恢复。

在客户端上,session 可以提供给 tls.connect()session 选项以恢复连接。

有关更多信息,请参阅 会话恢复

对于 TLSv1.2 及更低版本,一旦握手完成,就可以调用 tls.TLSSocket.getSession()。对于 TLSv1.3,协议仅允许基于票证的恢复,会发送多个票证,并且直到握手完成后才发送票证。因此,有必要等待 'session' 事件以获取可恢复的会话。应用程序应使用 'session' 事件而不是 getSession() 以确保它们适用于所有 TLS 版本。仅期望获取或使用一个会话的应用程序应仅侦听此事件一次

tlsSocket.once('session', (session) => {
  // The session can be used immediately or later.
  tls.connect({
    session: session,
    // Other connect options...
  });
}); 

tlsSocket.address()#

返回底层套接字的绑定 address、地址 family 名称和 port,如操作系统所报告:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }

tlsSocket.authorizationError#

返回对等证书未经验证的原因。仅当 tlsSocket.authorized === false 时才设置此属性。

tlsSocket.authorized#

如果对等证书是由创建 tls.TLSSocket 实例时指定的某个 CA 签名的,则此属性为 true,否则为 false

tlsSocket.disableRenegotiation()#

禁用此 TLSSocket 实例的 TLS 重新协商。一旦调用,重新协商尝试将在 TLSSocket 上触发一个 'error' 事件。

tlsSocket.enableTrace()#

启用后,TLS 数据包跟踪信息将写入 stderr。这可用于调试 TLS 连接问题。

输出格式与 openssl s_client -traceopenssl s_server -trace 的输出格式相同。虽然它是由 OpenSSL 的 SSL_trace() 函数生成的,但该格式未记录,可能会在不通知的情况下更改,因此不应依赖它。

tlsSocket.encrypted#

始终返回 true。这可用于区分 TLS 套接字和常规 net.Socket 实例。

tlsSocket.exportKeyingMaterial(length, label[, context])#

密钥材料用于验证,以防止网络协议中出现不同类型的攻击,例如在 IEEE 802.1X 的规范中。

示例

const keyingMaterial = tlsSocket.exportKeyingMaterial(
  128,
  'client finished');

/*
 Example return value of keyingMaterial:
 <Buffer 76 26 af 99 c5 56 8e 42 09 91 ef 9f 93 cb ad 6c 7b 65 f8 53 f1 d8 d9
    12 5a 33 b8 b5 25 df 7b 37 9f e0 e2 4f b8 67 83 a3 2f cd 5d 41 42 4c 91
    74 ef 2c ... 78 more bytes>
*/ 

有关更多信息,请参阅 OpenSSL SSL_export_keying_material 文档。

tlsSocket.getCertificate()#

返回表示本地证书的对象。返回的对象具有一些与证书字段相对应的属性。

有关证书结构的示例,请参阅 tls.TLSSocket.getPeerCertificate()

如果没有本地证书,将返回一个空对象。如果套接字已被销毁,将返回 null

tlsSocket.getCipher()#

返回一个包含协商密码套件信息的的对象。

例如,具有 AES256-SHA 密码的 TLSv1.2 协议

{
    "name": "AES256-SHA",
    "standardName": "TLS_RSA_WITH_AES_256_CBC_SHA",
    "version": "SSLv3"
} 

有关更多信息,请参阅 SSL_CIPHER_get_name

tlsSocket.getEphemeralKeyInfo()#

返回一个对象,表示客户端连接上的 完美前向保密 中临时密钥交换的类型、名称和参数大小。当密钥交换不是临时时,它返回一个空对象。由于仅在客户端套接字上支持此功能;如果在服务器套接字上调用,则返回 null。支持的类型为 'DH''ECDH'name 属性仅在类型为 'ECDH' 时可用。

例如:{ type: 'ECDH', name: 'prime256v1', size: 256 }

tlsSocket.getFinished()#

  • 返回:<Buffer> | <undefined> 作为 SSL/TLS 握手的一部分已发送到套接字的最新 Finished 消息,或者如果尚未发送 Finished 消息,则返回 undefined

由于 Finished 消息是完整握手的消息摘要(对于 TLS 1.0 总共 192 位,对于 SSL 3.0 更多),因此当 SSL/TLS 提供的身份验证不受需要或不足时,它们可用于外部身份验证过程。

对应于 OpenSSL 中的 SSL_get_finished 例程,可用于实现 RFC 5929 中的 tls-unique 通道绑定。

tlsSocket.getPeerCertificate([detailed])#

  • detailed <boolean> 如果为 true,则包括完整的证书链,否则仅包括对等方的证书。
  • 返回:<Object> 证书对象。

返回一个表示对等证书的对象。如果对等方未提供证书,将返回一个空对象。如果套接字已被销毁,将返回 null

如果请求了完整证书链,每个证书都将包含一个 issuerCertificate 属性,其中包含一个表示其颁发者证书的对象。

证书对象#

证书对象具有与证书字段相对应的属性。

  • ca <boolean> 如果是证书颁发机构 (CA),则为 true,否则为 false
  • raw <Buffer> DER 编码的 X.509 证书数据。
  • subject <Object> 证书主体,以国家/地区 (C)、州或省 (ST)、城市 (L)、组织 (O)、组织单位 (OU) 和公用名 (CN) 描述。公用名通常是带有 TLS 证书的 DNS 名称。示例:{C: 'UK', ST: 'BC', L: 'Metro', O: 'Node Fans', OU: 'Docs', CN: 'example.com'}
  • issuer <Object> 证书颁发者,以与 subject 相同的术语描述。
  • valid_from <string> 证书有效开始的日期时间。
  • valid_to <string> 证书有效结束的日期时间。
  • serialNumber <string> 证书序列号,作为十六进制字符串。示例:'B9B0D332A1AA5635'
  • fingerprint <string> DER 编码证书的 SHA-1 摘要。它以 : 分隔的十六进制字符串返回。示例:'2A:7A:C2:DD:...'
  • fingerprint256 <string> DER 编码证书的 SHA-256 摘要。它以 : 分隔的十六进制字符串返回。示例:'2A:7A:C2:DD:...'
  • fingerprint512 <string> DER 编码证书的 SHA-512 摘要。它以 : 分隔的十六进制字符串返回。示例:'2A:7A:C2:DD:...'
  • ext_key_usage <Array>(可选)扩展密钥用法,一组 OID。
  • subjectaltname <string>(可选)包含主题连接名称的字符串,作为 subject 名称的替代。
  • infoAccess <Array>(可选)描述 AuthorityInfoAccess 的数组,与 OCSP 一起使用。
  • issuerCertificate <Object>(可选)颁发者证书对象。对于自签名证书,这可能是一个循环引用。

证书可能包含有关公钥的信息,具体取决于密钥类型。

对于 RSA 密钥,可以定义以下属性

  • bits <number> RSA 位大小。示例:1024
  • exponent <string> RSA 指数,作为十六进制数字表示的字符串。示例:'0x010001'
  • modulus <string> RSA 模数,作为十六进制字符串。示例:'B56CE45CB7...'
  • pubkey <Buffer> 公钥。

对于 EC 密钥,可以定义以下属性

  • pubkey <Buffer> 公钥。
  • bits <number> 密钥大小(以位为单位)。示例:256
  • asn1Curve <string>(可选)椭圆曲线的 OID 的 ASN.1 名称。已知曲线由 OID 标识。虽然不常见,但曲线可能由其数学属性标识,在这种情况下它将没有 OID。示例:'prime256v1'
  • nistCurve <string>(可选)椭圆曲线的 NIST 名称(如果存在,并非所有已知曲线都已由 NIST 分配名称)。示例:'P-256'

证书示例

{ subject:
   { OU: [ 'Domain Control Validated', 'PositiveSSL Wildcard' ],
     CN: '*.nodejs.org' },
  issuer:
   { C: 'GB',
     ST: 'Greater Manchester',
     L: 'Salford',
     O: 'COMODO CA Limited',
     CN: 'COMODO RSA Domain Validation Secure Server CA' },
  subjectaltname: 'DNS:*.nodejs.org, DNS:nodejs.org',
  infoAccess:
   { 'CA Issuers - URI':
      [ 'http://crt.comodoca.com/COMODORSADomainValidationSecureServerCA.crt' ],
     'OCSP - URI': [ 'http://ocsp.comodoca.com' ] },
  modulus: 'B56CE45CB740B09A13F64AC543B712FF9EE8E4C284B542A1708A27E82A8D151CA178153E12E6DDA15BF70FFD96CB8A88618641BDFCCA03527E665B70D779C8A349A6F88FD4EF6557180BD4C98192872BCFE3AF56E863C09DDD8BC1EC58DF9D94F914F0369102B2870BECFA1348A0838C9C49BD1C20124B442477572347047506B1FCD658A80D0C44BCC16BC5C5496CFE6E4A8428EF654CD3D8972BF6E5BFAD59C93006830B5EB1056BBB38B53D1464FA6E02BFDF2FF66CD949486F0775EC43034EC2602AEFBF1703AD221DAA2A88353C3B6A688EFE8387811F645CEED7B3FE46E1F8B9F59FAD028F349B9BC14211D5830994D055EEA3D547911E07A0ADDEB8A82B9188E58720D95CD478EEC9AF1F17BE8141BE80906F1A339445A7EB5B285F68039B0F294598A7D1C0005FC22B5271B0752F58CCDEF8C8FD856FB7AE21C80B8A2CE983AE94046E53EDE4CB89F42502D31B5360771C01C80155918637490550E3F555E2EE75CC8C636DDE3633CFEDD62E91BF0F7688273694EEEBA20C2FC9F14A2A435517BC1D7373922463409AB603295CEB0BB53787A334C9CA3CA8B30005C5A62FC0715083462E00719A8FA3ED0A9828C3871360A73F8B04A4FC1E71302844E9BB9940B77E745C9D91F226D71AFCAD4B113AAF68D92B24DDB4A2136B55A1CD1ADF39605B63CB639038ED0F4C987689866743A68769CC55847E4A06D6E2E3F1',
  exponent: '0x10001',
  pubkey: <Buffer ... >,
  valid_from: 'Aug 14 00:00:00 2017 GMT',
  valid_to: 'Nov 20 23:59:59 2019 GMT',
  fingerprint: '01:02:59:D9:C3:D2:0D:08:F7:82:4E:44:A4:B4:53:C5:E2:3A:87:4D',
  fingerprint256: '69:AE:1A:6A:D4:3D:C6:C1:1B:EA:C6:23:DE:BA:2A:14:62:62:93:5C:7A:EA:06:41:9B:0B:BC:87:CE:48:4E:02',
  fingerprint512: '19:2B:3E:C3:B3:5B:32:E8:AE:BB:78:97:27:E4:BA:6C:39:C9:92:79:4F:31:46:39:E2:70:E5:5F:89:42:17:C9:E8:64:CA:FF:BB:72:56:73:6E:28:8A:92:7E:A3:2A:15:8B:C2:E0:45:CA:C3:BC:EA:40:52:EC:CA:A2:68:CB:32',
  ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
  serialNumber: '66593D57F20CBC573E433381B5FEC280',
  raw: <Buffer ... > } 

tlsSocket.getPeerFinished()#

  • 返回:<Buffer> | <undefined> 预期或实际从套接字接收到的 SSL/TLS 握手的一部分的最新Finished消息,如果没有Finished消息,则为undefined

由于 Finished 消息是完整握手的消息摘要(对于 TLS 1.0 总共 192 位,对于 SSL 3.0 更多),因此当 SSL/TLS 提供的身份验证不受需要或不足时,它们可用于外部身份验证过程。

对应于 OpenSSL 中的SSL_get_peer_finished例程,可用于实现 RFC 5929 中的tls-unique通道绑定。

tlsSocket.getPeerX509Certificate()#

将对等证书返回为 <X509Certificate> 对象。

如果没有对等证书,或者套接字已被销毁,则将返回undefined

tlsSocket.getProtocol()#

返回一个包含当前连接的已协商 SSL/TLS 协议版本字符串。对于尚未完成握手过程的已连接套接字,将返回值'unknown'。对于服务器套接字或已断开连接的客户端套接字,将返回值null

协议版本为

  • “SSLv3”
  • “TLSv1”
  • “TLSv1.1”
  • “TLSv1.2”
  • “TLSv1.3”

有关更多信息,请参阅 OpenSSL SSL_get_version 文档。

tlsSocket.getSession()#

返回 TLS 会话数据,如果未协商会话,则返回 undefined。在客户端上,可以将数据提供给 tls.connect()session 选项以恢复连接。在服务器上,它可能对调试有用。

有关更多信息,请参阅 会话恢复

注意:getSession() 仅适用于 TLSv1.2 及更低版本。对于 TLSv1.3,应用程序必须使用 'session' 事件(它也适用于 TLSv1.2 及更低版本)。

tlsSocket.getSharedSigalgs()#

  • 返回:<Array> 服务器和客户端之间共享的签名算法列表,按优先级递减排列。

有关更多信息,请参阅 SSL_get_shared_sigalgs

tlsSocket.getTLSTicket()#

对于客户端,如果存在 TLS 会话票证,则返回该票证,否则返回 undefined。对于服务器,始终返回 undefined

它可能对调试有用。

有关更多信息,请参阅 会话恢复

tlsSocket.getX509Certificate()#

返回本地证书,作为 <X509Certificate> 对象。

如果没有本地证书,或者套接字已被销毁,则将返回 undefined

tlsSocket.isSessionReused()#

  • 返回:<boolean> 如果会话被重用,则返回 true,否则返回 false

有关更多信息,请参阅 会话恢复

tlsSocket.localAddress#

返回本地 IP 地址的字符串表示形式。

tlsSocket.localPort#

返回本地端口的数字表示。

tlsSocket.remoteAddress#

返回远程 IP 地址的字符串表示。例如,'74.125.127.100''2001:4860:a005::68'

tlsSocket.remoteFamily#

返回远程 IP 家族的字符串表示。'IPv4''IPv6'

tlsSocket.remotePort#

返回远程端口的数字表示。例如,443

tlsSocket.renegotiate(options, callback)#

  • options <Object>

    • rejectUnauthorized <boolean> 如果不为 false,则会根据提供的 CA 列表验证服务器证书。如果验证失败,则会发出 'error' 事件;err.code 包含 OpenSSL 错误代码。默认值:true
    • requestCert
  • callback <Function> 如果 renegotiate() 返回 true,则回调会附加到 'secure' 事件中一次。如果 renegotiate() 返回 false,则 callback 将在下一个 tick 中被调用,并带有错误,除非 tlsSocket 已被销毁,在这种情况下,callback 根本不会被调用。

  • 返回:<boolean> 如果已启动重新协商,则为 true,否则为 false

tlsSocket.renegotiate() 方法启动 TLS 重新协商进程。完成后,将向 callback 函数传递单个参数,该参数要么是 Error(如果请求失败),要么是 null

可以在建立安全连接后使用此方法来请求对等方的证书。

作为服务器运行时,在 handshakeTimeout 超时后,套接字将被销毁,并带有错误。

对于 TLSv1.3,无法启动重新协商,因为协议不支持它。

tlsSocket.setMaxSendFragment(size)#

  • size <number> 最大 TLS 片段大小。最大值为 16384默认值:16384
  • 返回:<boolean>

tlsSocket.setMaxSendFragment() 方法设置最大 TLS 片段大小。如果设置限制成功,则返回 true;否则返回 false

较小的片段大小会降低客户端上的缓冲延迟:较大的片段由 TLS 层缓冲,直到收到整个片段并验证其完整性;大片段可能跨越多个往返,并且由于丢包或重新排序,其处理可能会延迟。但是,较小的片段会增加额外的 TLS 帧字节和 CPU 开销,这可能会降低整体服务器吞吐量。

tls.checkServerIdentity(hostname, cert)#

验证证书 cert 是否颁发给 hostname

返回 <Error> 对象,在失败时填充 reasonhostcert。成功时,返回 <undefined>

此函数旨在与可传递给 tls.connect()checkServerIdentity 选项结合使用,并因此对 证书对象 进行操作。对于其他用途,请考虑改用 x509.checkHost()

此函数可以通过提供一个替代函数作为传递给 tls.connect()options.checkServerIdentity 选项来覆盖。当然,覆盖函数可以调用 tls.checkServerIdentity(),以通过其他验证来增强所做的检查。

仅当证书通过所有其他检查(例如由受信任的 CA(options.ca)颁发)时,才会调用此函数。

早期版本的 Node.js 错误地接受了给定 hostname 的证书,如果存在匹配的 uniformResourceIdentifier 主题备用名称(请参见 CVE-2021-44531)。希望接受 uniformResourceIdentifier 主题备用名称的应用程序可以使用自定义 options.checkServerIdentity 函数来实现所需的行为。

tls.connect(options[, callback])#

  • options <Object>
    • enableTrace:请参阅 tls.createServer()

    • host <string> 客户端应连接到的主机。默认值:'localhost'

    • port <number> 客户端应连接到的端口。

    • path <string> 创建到路径的 Unix 套接字连接。如果指定此选项,则忽略 hostport

    • socket <stream.Duplex> 在给定的套接字上建立安全连接,而不是创建新的套接字。通常,这是 net.Socket 的一个实例,但允许任何 Duplex 流。如果指定此选项,则忽略 pathhostport,但证书验证除外。通常,当传递给 tls.connect() 时,套接字已经连接,但它可以在稍后连接。socket 的连接/断开连接/销毁是用户的责任;调用 tls.connect() 不会导致调用 net.connect()

    • allowHalfOpen <boolean> 如果设置为 false,则当可读端结束时,套接字将自动结束可写端。如果设置了 socket 选项,则此选项无效。有关详细信息,请参阅 net.SocketallowHalfOpen 选项。默认值:false

    • rejectUnauthorized <boolean> 如果不为 false,则会根据提供的 CA 列表验证服务器证书。如果验证失败,则会发出 'error' 事件;err.code 包含 OpenSSL 错误代码。默认值:true

    • pskCallback <Function>

      • 提示: <string> 服务器发送的可选消息,以帮助客户端决定在协商期间使用哪个身份。如果使用 TLS 1.3,则始终为 null
      • 返回: <Object> 形式为 { psk: <Buffer|TypedArray|DataView>, identity: <string> } 的对象或 null 以停止协商过程。psk 必须与所选密码的摘要兼容。identity 必须使用 UTF-8 编码。

      在协商 TLS-PSK(预共享密钥)时,此函数将使用服务器提供的可选身份 hint 调用,或者在删除了 hint 的 TLS 1.3 中调用 null。有必要为连接提供自定义 tls.checkServerIdentity(),因为默认值将尝试根据证书检查服务器的主机名/IP,但这不适用于 PSK,因为不会存在证书。可以在 RFC 4279 中找到更多信息。

    • ALPNProtocols: <string[]> | <Buffer[]> | <TypedArray[]> | <DataView[]> | <Buffer> | <TypedArray> | <DataView> 字符串、BufferTypedArrayDataView 数组,或包含受支持 ALPN 协议的单个 BufferTypedArrayDataViewBuffer 应采用 [len][name][len][name]... 格式,例如 '\x08http/1.1\x08http/1.0',其中 len 字节是下一个协议名称的长度。传递数组通常简单得多,例如 ['http/1.1', 'http/1.0']。列表中较早的协议比较晚的协议具有更高的优先级。

    • servername: <string> SNI(服务器名称指示)TLS 扩展的服务器名称。它是所连接主机的名称,必须是主机名,而不是 IP 地址。多宿主服务器可以使用它来选择要向客户端显示的正确证书,请参阅 tls.createServer()SNICallback 选项。

    • checkServerIdentity(servername, cert) <Function> 在根据证书检查服务器的主机名(或在显式设置时提供的 servername)时要使用的回调函数(而不是内置 tls.checkServerIdentity() 函数)。如果验证失败,此函数应返回一个 <Error>。如果验证了 servernamecert,该方法应返回 undefined

    • session <Buffer> 包含 TLS 会话的 Buffer 实例。

    • minDHSize <number> 以位为单位的 DH 参数的最小大小,以接受 TLS 连接。当服务器提供的 DH 参数大小小于 minDHSize 时,TLS 连接将被销毁并引发错误。默认值:1024

    • highWaterMark: <number> 与可读流 highWaterMark 参数一致。默认值:16 * 1024

    • secureContext:使用 tls.createSecureContext() 创建的 TLS 上下文对象。如果 提供 secureContext,则将通过将整个 options 对象传递给 tls.createSecureContext() 来创建一个

    • onread <Object> 如果缺少 socket 选项,传入数据将存储在单个 buffer 中,并在套接字上收到数据时传递给提供的 callback,否则将忽略该选项。有关详细信息,请参阅 net.Socketonread 选项。

    • ...: tls.createSecureContext() 选项,如果缺少 secureContext 选项,则使用这些选项,否则将忽略这些选项。

    • ...: 任何尚未列出的 socket.connect() 选项。

  • callback <Function>
  • 返回:<tls.TLSSocket>

如果指定了 callback 函数,则会将其作为 'secureConnect' 事件的侦听器添加。

tls.connect() 返回一个 tls.TLSSocket 对象。

https API 不同,tls.connect() 默认情况下不会启用 SNI(服务器名称指示)扩展,这可能会导致一些服务器返回错误的证书或完全拒绝连接。要启用 SNI,请在 host 之外设置 servername 选项。

以下展示了 tls.createServer() 中 echo 服务器示例的客户端

// Assumes an echo server that is listening on port 8000.
const tls = require('node:tls');
const fs = require('node:fs');

const options = {
  // Necessary only if the server requires client certificate authentication.
  key: fs.readFileSync('client-key.pem'),
  cert: fs.readFileSync('client-cert.pem'),

  // Necessary only if the server uses a self-signed certificate.
  ca: [ fs.readFileSync('server-cert.pem') ],

  // Necessary only if the server's cert isn't for "localhost".
  checkServerIdentity: () => { return null; },
};

const socket = tls.connect(8000, options, () => {
  console.log('client connected',
              socket.authorized ? 'authorized' : 'unauthorized');
  process.stdin.pipe(socket);
  process.stdin.resume();
});
socket.setEncoding('utf8');
socket.on('data', (data) => {
  console.log(data);
});
socket.on('end', () => {
  console.log('server ends connection');
}); 

tls.connect(path[, options][, callback])#

tls.connect() 相同,只不过可以将 path 作为参数提供,而不是作为选项提供。

如果指定了 path 选项,则该选项将优先于 path 参数。

tls.connect(port[, host][, options][, callback])#

tls.connect() 相同,只不过可以将 porthost 作为参数提供,而不是作为选项提供。

如果指定了 port 或 host 选项,则该选项将优先于任何 port 或 host 参数。

tls.createSecureContext([options])#

  • options <Object>
    • ca <string> | <string[]> | <Buffer> | <Buffer[]> 可选地覆盖受信任的 CA 证书。默认情况下,信任 Mozilla 策划的众所周知的 CA。当使用此选项显式指定 CA 时,Mozilla 的 CA 将被完全替换。该值可以是字符串或 Buffer,也可以是字符串和/或 BufferArray。任何字符串或 Buffer 都可以包含多个 PEM CA 连接在一起。对等方的证书必须可以链接到服务器信任的 CA,才能对连接进行身份验证。当使用无法链接到众所周知的 CA 的证书时,必须将证书的 CA 显式指定为受信任的,否则连接将无法通过身份验证。如果对等方使用与默认 CA 不匹配或不链接的证书,请使用 ca 选项提供对等方的证书可以匹配或链接到的 CA 证书。对于自签名证书,证书是其自己的 CA,并且必须提供。对于 PEM 编码的证书,支持的类型为“受信任的证书”、“X509 证书”和“证书”。另请参阅 tls.rootCertificates
    • cert <string> | <string[]> | <Buffer> | <Buffer[]> PEM 格式的证书链。每个私钥应提供一个证书链。每个证书链应由提供的私有 key 的 PEM 格式证书组成,然后按顺序排列 PEM 格式的中间证书(如果有),但不包括根 CA(根 CA 必须是同行预先知道的,请参阅 ca)。提供多个证书链时,它们不必与 key 中的私钥顺序相同。如果未提供中间证书,对等方将无法验证证书,握手将失败。
    • sigalgs <string> 用冒号分隔的支持签名算法列表。该列表可以包含摘要算法(SHA256MD5 等)、公钥算法(RSA-PSSECDSA 等)、两者的组合(例如“RSA+SHA384”)或 TLS v1.3 方案名称(例如 rsa_pss_pss_sha512)。有关更多信息,请参阅 OpenSSL 手册页
    • ciphers <string> 密码套件规范,替换默认值。有关更多信息,请参阅 修改默认 TLS 密码套件。可以通过 tls.getCiphers() 获取允许的密码。为了让 OpenSSL 接受密码名称,密码名称必须大写。
    • clientCertEngine <string> 可以提供客户端证书的 OpenSSL 引擎的名称。
    • crl <string> | <string[]> | <Buffer> | <Buffer[]> PEM 格式的 CRL(证书吊销列表)。
    • dhparam <string> | <Buffer> 'auto' 或自定义 Diffie-Hellman 参数,非 ECDHE 完全前向保密 所需。如果省略或无效,参数将被静默丢弃,并且 DHE 密码将不可用。基于 ECDHE完全前向保密 仍然可用。
    • ecdhCurve <string> 一个描述命名曲线或用冒号分隔的曲线 NID 或名称的字符串,例如 P-521:P-384:P-256,用于 ECDH 密钥协商。设置为 auto 以自动选择曲线。使用 crypto.getCurves() 获取可用曲线名称列表。在最新版本中,openssl ecparam -list_curves 也将显示每个可用椭圆曲线的名称和描述。默认值: tls.DEFAULT_ECDH_CURVE
    • honorCipherOrder <boolean> 尝试使用服务器的密码套件偏好设置,而不是客户端的。当 true 时,会导致在 secureOptions 中设置 SSL_OP_CIPHER_SERVER_PREFERENCE,有关更多信息,请参阅 OpenSSL 选项
    • key <string> | <string[]> | <Buffer> | <Buffer[]> | <Object[]> PEM 格式的私钥。PEM 允许对私钥进行加密。加密的密钥将使用 options.passphrase 解密。可以使用不同的算法提供多个密钥,它们可以是未加密的密钥字符串或缓冲区的数组,也可以是形式为 {pem: <string|buffer>[, passphrase: <string>]} 的对象数组。对象形式只能出现在数组中。object.passphrase 是可选的。如果提供了 object.passphrase,则使用它来解密加密的密钥,否则使用 options.passphrase
    • privateKeyEngine <string> 从中获取私钥的 OpenSSL 引擎的名称。应与 privateKeyIdentifier 一起使用。
    • privateKeyIdentifier <string> 由 OpenSSL 引擎管理的私钥的标识符。应与 privateKeyEngine 一起使用。不应与 key 一起设置,因为这两个选项以不同的方式定义私钥。
    • maxVersion <string> 可选地设置允许的最大 TLS 版本。'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1' 之一。不能与 secureProtocol 选项一起指定;使用其中一个选项。默认: tls.DEFAULT_MAX_VERSION
    • minVersion <string> 可选地设置允许的最小 TLS 版本。'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1' 之一。不能与 secureProtocol 选项一起指定;使用其中一个选项。避免将设置低于 TLSv1.2,但为了实现互操作性,这可能是必需的。默认: tls.DEFAULT_MIN_VERSION
    • passphrase <string> 用于单个私钥和/或 PFX 的共享密码。
    • pfx <string> | <string[]> | <Buffer> | <Buffer[]> | <Object[]> PFX 或 PKCS12 编码的私钥和证书链。pfx 是单独提供 keycert 的替代方案。PFX 通常是加密的,如果是,passphrase 将用于解密它。可以将多个 PFX 提供为未加密的 PFX 缓冲区的数组,或以 {buf: <string|buffer>[, passphrase: <string>]} 形式的对象数组。对象形式只能出现在数组中。object.passphrase 是可选的。如果提供了 object.passphrase,将使用它来解密加密的 PFX,如果没有提供,则使用 options.passphrase
    • secureOptions <number> 可选择影响 OpenSSL 协议行为,通常没有必要。如果使用,应谨慎使用!值是 OpenSSL 选项SSL_OP_* 选项的数字位掩码。
    • secureProtocol <string> 选择要使用的 TLS 协议版本的旧机制,它不支持独立控制最小版本和最大版本,也不支持将协议限制为 TLSv1.3。请改用 minVersionmaxVersion。可能的取值列为 SSL_METHODS,使用函数名称作为字符串。例如,使用 'TLSv1_1_method' 来强制使用 TLS 版本 1.1,或使用 'TLS_method' 来允许任何 TLS 协议版本(最高到 TLSv1.3)。不建议使用低于 1.2 的 TLS 版本,但为了实现互操作性,可能需要使用。默认值:无,请参阅 minVersion
    • sessionIdContext <string> 服务器用来确保会话状态不会在应用程序之间共享的不透明标识符。客户端不使用。
    • ticketKeys: <Buffer> 48 字节的密码学强伪随机数据。有关更多信息,请参阅 会话恢复
    • sessionTimeout <number> 服务器创建的 TLS 会话在该时间(以秒为单位)后将不再可恢复。有关更多信息,请参阅 会话恢复默认值:300

tls.createServer()honorCipherOrder 选项的默认值设置为 true,创建安全上下文的其他 API 会将其保留为未设置状态。

tls.createServer() 使用从 process.argv 生成的 128 位截断 SHA1 哈希值作为 sessionIdContext 选项的默认值,创建安全上下文的其他 API 没有默认值。

tls.createSecureContext() 方法创建一个 SecureContext 对象。它可用作多个 tls API 的参数,例如 server.addContext(),但没有公共方法。tls.Server 构造函数和 tls.createServer() 方法不支持 secureContext 选项。

使用证书的密码需要一个密钥。keypfx 都可用于提供它。

如果未提供 ca 选项,则 Node.js 将默认使用 Mozilla 公开可信的 CA 列表

不建议使用自定义 DHE 参数,而建议使用新的 dhparam: 'auto' 选项。将此选项设置为 'auto' 时,将自动选择强度足够的众所周知的 DHE 参数。否则,如有必要,可以使用 openssl dhparam 创建自定义参数。密钥长度必须大于或等于 1024 位,否则将引发错误。虽然 1024 位是可以接受的,但为了更强的安全性,请使用 2048 位或更大的密钥长度。

tls.createSecurePair([context][, isServer][, requestCert][, rejectUnauthorized][, options])#

稳定性:0 - 已弃用:改用 tls.TLSSocket

  • context <Object>tls.createSecureContext() 返回的安全上下文对象
  • isServer <boolean> true 表示此 TLS 连接应作为服务器打开。
  • requestCert <boolean> true 表示服务器是否应从连接客户端请求证书。仅当 isServertrue 时适用。
  • rejectUnauthorized <boolean> 如果不为 false,服务器将自动拒绝具有无效证书的客户端。仅当 isServertrue 时适用。
  • options

创建一个具有两个流的新安全对对象,其中一个流读取和写入加密数据,另一个流读取和写入明文数据。通常,加密流会管道到/从传入的加密数据流,而明文流会用作初始加密流的替代项。

tls.createSecurePair() 返回一个 tls.SecurePair 对象,其中包含 cleartextencrypted 流属性。

使用 cleartext 具有与 tls.TLSSocket 相同的 API。

现在 tls.createSecurePair() 方法已弃用,建议使用 tls.TLSSocket()。例如,代码

pair = tls.createSecurePair(/* ... */);
pair.encrypted.pipe(socket);
socket.pipe(pair.encrypted); 

可替换为

secureSocket = tls.TLSSocket(socket, options); 

其中 secureSocket 具有与 pair.cleartext 相同的 API。

tls.createServer([options][, secureConnectionListener])#

  • options <Object>
    • ALPNProtocols<string[]> | <Buffer[]> | <TypedArray[]> | <DataView[]> | <Buffer> | <TypedArray> | <DataView> 一个字符串、BufferTypedArrayDataView 数组,或一个包含受支持 ALPN 协议的 BufferTypedArrayDataViewBuffer 应采用格式 [len][name][len][name]...,例如 0x05hello0x05world,其中第一个字节是下一个协议名称的长度。传递一个数组通常简单得多,例如 ['hello', 'world']。(协议应按其优先级排序。)

    • ALPNCallback: <Function> 如果设置,当客户端使用 ALPN 扩展打开连接时,将调用此函数。将向回调传递一个参数:一个包含 servernameprotocols 字段的对象,分别包含来自 SNI 扩展(如果存在)的服务器名称和 ALPN 协议名称字符串数组。回调必须返回 protocols 中列出的一个字符串,该字符串将作为选定的 ALPN 协议返回给客户端,或返回 undefined,以通过致命警报拒绝连接。如果返回的字符串与客户端的 ALPN 协议之一不匹配,将引发错误。此选项不能与 ALPNProtocols 选项一起使用,并且设置这两个选项将引发错误。

    • clientCertEngine <string> 可以提供客户端证书的 OpenSSL 引擎的名称。

    • enableTrace <boolean> 如果为 true,则将在新连接上调用 tls.TLSSocket.enableTrace()。可以在建立安全连接后启用跟踪,但必须使用此选项来跟踪安全连接设置。默认值: false

    • handshakeTimeout <number> 如果 SSL/TLS 握手未在指定毫秒数内完成,则中止连接。每当握手超时时,tls.Server 对象上都会发出 'tlsClientError'默认值: 120000(120 秒)。

    • rejectUnauthorized <boolean> 如果不为 false,服务器将拒绝未经提供的 CA 列表授权的任何连接。只有当 requestCerttrue 时,此选项才有效。默认值: true

    • requestCert <boolean> 如果为 true,服务器将向连接的客户端请求证书,并尝试验证该证书。默认值: false

    • sessionTimeout <number> 服务器创建的 TLS 会话在该时间(以秒为单位)后将不再可恢复。有关更多信息,请参阅 会话恢复默认值:300

    • SNICallback(servername, callback) <Function> 如果客户端支持 SNI TLS 扩展,将调用此函数。调用时将传递两个参数:servernamecallbackcallback 是一个错误优先的回调,它接受两个可选参数:errorctx。如果提供,ctx 是一个 SecureContext 实例。可以使用 tls.createSecureContext() 来获取适当的 SecureContext。如果使用错误的 ctx 参数调用 callback,则将使用服务器的默认安全上下文。如果未提供 SNICallback,则将使用带有高级 API 的默认回调(见下文)。

    • ticketKeys: <Buffer> 48 字节的密码学强伪随机数据。有关更多信息,请参阅 会话恢复

    • pskCallback <Function>

      在协商 TLS-PSK(预共享密钥)时,此函数将使用客户端提供的身份进行调用。如果返回值为 null,协商过程将停止,并且会向另一方发送“unknown_psk_identity”警报消息。如果服务器希望隐藏 PSK 身份未知这一事实,则回调必须提供一些随机数据作为 psk,以便在协商完成之前,连接因“decrypt_error”而失败。默认情况下,PSK 密码被禁用,因此使用 TLS-PSK 需要使用 ciphers 选项明确指定密码套件。更多信息,请参阅 RFC 4279

    • pskIdentityHint <string> 可选提示,在 TLS-PSK 协商期间发送给客户端,以帮助选择身份。在 TLS 1.3 中将被忽略。如果未能设置 pskIdentityHint,则会发出 'tlsClientError',其中包含 'ERR_TLS_PSK_SET_IDENTIY_HINT_FAILED' 代码。

    • ...: 可以提供任何 tls.createSecureContext() 选项。对于服务器,通常需要身份选项(pfxkey/certpskCallback)。

    • ...: 可以提供任何 net.createServer() 选项。

  • secureConnectionListener <Function>
  • 返回:<tls.Server>

创建一个新的 tls.Server。如果提供了 secureConnectionListener,则会自动将其设置为 'secureConnection' 事件的侦听器。

ticketKeys 选项会在 node:cluster 模块工作进程之间自动共享。

以下内容说明了一个简单的回显服务器

const tls = require('node:tls');
const fs = require('node:fs');

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

  // This is necessary only if using client certificate authentication.
  requestCert: true,

  // This is necessary only if the client uses a self-signed certificate.
  ca: [ fs.readFileSync('client-cert.pem') ],
};

const server = tls.createServer(options, (socket) => {
  console.log('server connected',
              socket.authorized ? 'authorized' : 'unauthorized');
  socket.write('welcome!\n');
  socket.setEncoding('utf8');
  socket.pipe(socket);
});
server.listen(8000, () => {
  console.log('server bound');
}); 

可以通过使用 tls.connect() 中的示例客户端连接到服务器来测试服务器。

tls.getCiphers()#

返回一个数组,其中包含受支持的 TLS 密码的名称。出于历史原因,这些名称采用小写形式,但必须采用大写形式才能用于 tls.createSecureContext()ciphers 选项中。

并非所有受支持的密码都默认启用。请参阅 修改默认 TLS 密码套件

'tls_' 开头的密码名称适用于 TLSv1.3,所有其他名称适用于 TLSv1.2 及更低版本。

console.log(tls.getCiphers()); // ['aes128-gcm-sha256', 'aes128-sha', ...] 

tls.rootCertificates#

一个不可变字符串数组,表示当前 Node.js 版本提供的捆绑 Mozilla CA 存储中的根证书(PEM 格式)。

Node.js 提供的捆绑 CA 存储是 Mozilla CA 存储的快照,在发布时固定。它在所有受支持的平台上都是相同的。

tls.DEFAULT_ECDH_CURVE#

在 tls 服务器中用于 ECDH 密钥协商的默认曲线名称。默认值为 'auto'。有关更多信息,请参阅 tls.createSecureContext()

tls.DEFAULT_MAX_VERSION#

  • <string> tls.createSecureContext()maxVersion 选项的默认值。可以为其分配任何受支持的 TLS 协议版本,包括 'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'默认值: 'TLSv1.3',除非使用 CLI 选项进行更改。使用 --tls-max-v1.2 将默认值设置为 'TLSv1.2'。使用 --tls-max-v1.3 将默认值设置为 'TLSv1.3'。如果提供了多个选项,则使用最高的最大值。

tls.DEFAULT_MIN_VERSION#

  • <string> tls.createSecureContext()minVersion 选项的默认值。可以为其分配任何受支持的 TLS 协议版本,包括 'TLSv1.3''TLSv1.2''TLSv1.1''TLSv1'默认值: 'TLSv1.2',除非使用 CLI 选项进行更改。使用 --tls-min-v1.0 将默认值设置为 'TLSv1'。使用 --tls-min-v1.1 将默认值设置为 'TLSv1.1'。使用 --tls-min-v1.3 将默认值设置为 'TLSv1.3'。如果提供了多个选项,则使用最低的最小值。

tls.DEFAULT_CIPHERS#

  • <string> ciphers 选项的默认值 tls.createSecureContext()。它可以分配任何受支持的 OpenSSL 密码。默认为 crypto.constants.defaultCoreCipherList 的内容,除非使用 --tls-default-ciphers 使用 CLI 选项进行更改。