TLS (SSL)
History
稳定性:2 - 稳定
node:tls 模块提供了基于 OpenSSL 构建的传输层安全 (TLS) 和安全套接字层 (SSL) 协议的实现。可以使用以下方式访问该模块:
import tls from 'node:tls';Node.js 有可能在不包含 node:crypto 模块支持的情况下构建。在这种情况下,尝试从 tls import 或调用 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 时,如果代码可能在未启用 crypto 支持的 Node.js 构建上运行,请考虑使用 import() 函数而不是词法 import 关键字:
let tls;
try {
tls = await import('node:tls');
} catch (err) {
console.error('tls support is disabled!');
}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 握手随机生成密钥对来实现的(与对所有会话使用相同密钥相反)。实现此技术的方法称为“临时” (ephemeral)。
目前常用两种方法来实现完美前向保密(注意传统缩写后附加的字符 "E"):
默认启用使用 ECDHE 的完美前向保密。创建 TLS 服务器时可以使用 ecdhCurve 选项来自定义要使用的支持 ECDH 曲线列表。有关更多信息,请参见 tls.createServer()。
DHE 默认禁用,但可以通过将 dhparam 选项设置为 'auto' 与 ECDHE 一起启用。也支持自定义 DHE 参数,但不推荐使用,而是倾向于自动选择的知名参数。
完美前向保密在 TLSv1.2 之前是可选的。自 TLSv1.3 起,(EC)DHE 始终使用(仅 PSK 连接除外)。
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 检索。
在客户端连接上,应该传递自定义 checkServerIdentity,因为默认的那个在没有证书的情况下会失败。
根据 RFC 4279,必须支持长度高达 128 字节的 PSK 身份和长度高达 64 字节的 PSK。截至 OpenSSL 1.1.0,最大身份大小为 128 字节,最大 PSK 长度为 256 字节。
由于底层 OpenSSL API 的限制,当前实现不支持异步 PSK 回调。
要使用 TLS-PSK,客户端和服务器必须指定 pskCallback 选项,这是一个返回要使用的 PSK 的函数(必须与所选密码的摘要兼容)。
它将首先在客户端被调用:
然后在服务器上:
返回值 null 会停止协商过程并向另一方发送 unknown_psk_identity 警报消息。
如果服务器希望隐藏 PSK 身份未知的事实,回调必须提供一些随机数据作为 psk,以便在协商完成之前使连接因 decrypt_error 而失败。
TLS 协议允许客户端重新协商 TLS 会话的某些方面。不幸的是,会话重新协商需要不成比例的服务器端资源,使其成为拒绝服务攻击的潜在载体。
为了降低风险,重新协商限制为每十分钟三次。当超过此阈值时,tls.TLSSocket 实例上会发出 'error' 事件。限制是可配置的:
除非完全理解含义和风险,否则不应修改默认重新协商限制。
TLSv1.3 不支持重新协商。
建立 TLS 会话可能相对较慢。可以通过保存并稍后重用会话状态来加快此过程。有几种机制可以做到这一点,此处从最旧到最新(且首选)进行讨论。
服务器为新连接生成唯一 ID 并将其发送给客户端。客户端和服务器保存会话状态。重新连接时,客户端发送其保存会话状态的 ID,如果服务器也有该 ID 的状态,则可以同意使用它。否则,服务器将创建新会话。有关更多信息,请参见 RFC 2246,第 23 页和 30 页。
大多数 Web 浏览器在进行 HTTPS 请求时支持使用会话标识符恢复。
对于 Node.js,客户端等待 'session' 事件以获取会话数据,并将数据提供给后续 tls.connect() 的 session 选项以重用会话。服务器必须实现 'newSession' 和 'resumeSession' 事件的处理程序,以使用会话 ID 作为查找键来保存和恢复会话数据以重用会话。要在负载均衡器或集群 worker 之间复用会话,服务器必须在其会话处理程序中使用共享会话缓存(例如 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 验证服务器是否正在恢复会话。例如,对 openssl s_client 使用 -reconnect 选项:
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-SHA256Node.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要验证,请使用以下命令显示设置的加密套件列表,注意 defaultCoreCipherList 和 defaultCipherList 之间的区别:
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 变量,这必须在监听任何套接字之前执行,它不会影响已经打开的套接字。例如:
// 移除过时的 CBC 加密套件和基于 RSA 密钥交换的加密套件,因为它们不提供前向保密
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 而不是 TLSv1.2。
Node.js 中包含的默认加密套件经过精心选择,以反映当前的安全最佳实践和风险缓解措施。更改默认加密套件可能会对应用程序的安全性产生重大影响。只有在绝对必要时才应使用 --tls-cipher-list 开关和 ciphers 选项。
默认加密套件首选 GCM 加密套件以符合 Chrome 的“现代加密”设置,并且首选 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'
前三个默认启用。两个基于 CCM 的套件受 TLSv1.3 支持,因为它们在受限系统上可能性能更高,但它们默认未启用,因为它们提供的安全性较低。
OpenSSL 库强制执行安全级别以控制加密操作可接受的最低安全级别。OpenSSL 的安全级别范围从 0 到 5,每个级别都施加更严格的安全要求。默认安全级别是 2,通常适合大多数现代应用程序。但是,某些旧版功能和协议(如 TLSv1)需要较低的安全级别(SECLEVEL=0)才能正常运行。有关更详细的信息,请参阅 OpenSSL 关于安全级别的文档。
要在 Node.js 应用程序中调整安全级别,您可以在加密套件字符串中包含 @SECLEVEL=X,其中 X 是所需的安全级别。例如,要在使用默认 OpenSSL 加密套件列表时将安全级别设置为 0,您可以使用:
import { createServer, connect } from 'node:tls';
const port = 443;
createServer({ ciphers: 'DEFAULT@SECLEVEL=0', minVersion: 'TLSv1' }, function(socket) {
console.log('Client connected with protocol:', socket.getProtocol());
socket.end();
this.close();
})
.listen(port, () => {
connect(port, { ciphers: 'DEFAULT@SECLEVEL=0', maxVersion: 'TLSv1' });
});此方法将安全级别设置为 0,允许使用旧版功能,同时仍利用默认 OpenSSL 加密套件。
您也可以使用 --tls-cipher-list=DEFAULT@SECLEVEL=X 从命令行设置安全级别和加密套件,如 修改默认 TLS 加密套件 中所述。但是,通常不推荐使用命令行选项来设置加密套件,最好在应用程序代码中为各个上下文配置加密套件,因为这种方法提供更细粒度的控制,并降低全局降低安全级别的风险。
多个函数可能因 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': 主机名不匹配。
当发生诸如 UNABLE_TO_VERIFY_LEAF_SIGNATURE、DEPTH_ZERO_SELF_SIGNED_CERT 或 UNABLE_TO_GET_ISSUER_CERT 之类的证书错误时,Node.js 会附加一个提示,建议如果根 CA 本地安装,尝试使用 --use-system-ca 标志运行,以引导开发人员走向安全的解决方案,防止不安全的工作区。
类:tls.Server
History
- 继承:
<net.Server>
接受使用 TLS 或 SSL 的加密连接。
事件:'connection'
History
<stream.Duplex>当建立新的 TCP 流时,在 TLS 握手开始之前发出此事件。socket 通常是 net.Socket 类型的对象,但与 net.Server 'connection' 事件创建的套接字不同,它不会接收事件。通常用户不想访问此事件。
用户也可以显式发出此事件以将连接注入 TLS 服务器。在这种情况下,可以传递任何 Duplex 流。
事件:'keylog'
History
line{Buffer} ASCII 文本行,采用 NSSSSLKEYLOGFILE格式。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; // 仅记录特定 IP 的密钥
logFile.write(line);
});事件:'newSession'
History
The callback argument is now supported.
创建新的 TLS 会话时发出 'newSession' 事件。这可用于将会话存储在外部存储中。数据应提供给 'resumeSession' 回调。
调用监听器回调时传递三个参数:
sessionId{Buffer} TLS 会话标识符sessionData{Buffer} TLS 会话数据callback<Function>一个不带参数的回调函数,必须调用该函数才能通过安全连接发送或接收数据。
监听此事件仅对添加事件监听器后建立的连接有效。
事件:'OCSPRequest'
History
当客户端发送证书状态请求时发出 'OCSPRequest' 事件。调用监听器回调时传递三个参数:
certificate{Buffer} 服务器证书issuer{Buffer} 颁发者的证书callback<Function>必须调用以提供 OCSP 请求结果的回调函数。
可以解析服务器的当前证书以获取 OCSP URL 和证书 ID;获得 OCSP 响应后,然后调用 callback(null, resp),其中 resp 是包含 OCSP 响应的 Buffer 实例。certificate 和 issuer 都是主证书和颁发者证书的 Buffer DER 表示。这些可用于获取 OCSP 证书 ID 和 OCSP 端点 URL。
或者,可以调用 callback(null, null),表示没有 OCSP 响应。
调用 callback(err) 将导致 socket.destroy(err) 调用。
OCSP 请求的典型流程如下:
- 客户端连接到服务器并发送
'OCSPRequest'(通过 ClientHello 中的状态信息扩展)。 - 服务器接收请求并发出
'OCSPRequest'事件,如果已注册则调用监听器。 - 服务器从
certificate或issuer提取 OCSP URL 并向 CA 执行 OCSP 请求。 - 服务器从 CA 接收
'OCSPResponse'并通过callback参数将其发送回客户端 - 客户端验证响应并销毁套接字或执行握手。
如果证书是自签名的或颁发者不在根证书列表中,则 issuer 可以为 null。(建立 TLS 连接时可以通过 ca 选项提供颁发者。)
监听此事件仅对添加事件监听器后建立的连接有效。
可以使用像 asn1.js 这样的 npm 模块来解析证书。
事件:'resumeSession'
History
当客户端请求恢复以前的 TLS 会话时发出 'resumeSession' 事件。调用监听器回调时传递两个参数:
sessionId{Buffer} TLS 会话标识符callback<Function>当恢复先前会话时调用的回调函数:callback([err[, sessionData]])Attributeserr:<Error>sessionData:{Buffer}
事件监听器应使用给定的 sessionId 在外部存储中查找由 'newSession' 事件处理程序保存的 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'
History
新连接的握手过程成功完成后发出 'secureConnection' 事件。调用监听器回调时传递一个参数:
<tls.TLSSocket>tlsSocket.authorized 属性是一个 boolean,指示客户端是否已由服务器提供的证书授权机构之一验证。如果 tlsSocket.authorized 为 false,则 socket.authorizationError 设置为描述授权失败的原因。根据 TLS 服务器的设置,可能仍会接受未经授权的连接。
tlsSocket.alpnProtocol 属性是一个包含所选 ALPN 协议的字符串。当 ALPN 没有所选协议(因为客户端或服务器未发送 ALPN 扩展)时,tlsSocket.alpnProtocol 等于 false。
tlsSocket.servername 属性是一个包含通过 SNI 请求的服务器名称的字符串。
事件:'tlsClientError'
History
在建立安全连接之前发生错误时发出 'tlsClientError' 事件。调用监听器回调时传递两个参数:
<Error>Error
对象<tls.TLSSocket>tls.TLSSocket
实例。server.addContext(hostname, context): void<string>'*'
)<Object>
|
<tls.SecureContext>tls.createSecureContext()
options
参数的任何可能属性(例如
key
、
cert
、
ca
等),或使用
tls.createSecureContext()
本身创建的 TLS 上下文对象。server.addContext() 方法添加一个安全上下文,如果客户端请求的 SNI 名称与提供的 hostname(或通配符)匹配,则将使用该上下文。
当有多个匹配的上下文时,使用最近添加的一个。
server.address(): void- 返回:
<Object>
返回操作系统报告的服务器绑定地址、地址族名称和端口。有关更多信息,请参阅 net.Server.address()。
server.close(callback?): void<Function>'close'
事件。<tls.Server>server.close() 方法停止服务器接受新连接。
此函数异步运行。当服务器没有更多打开的连接时,将发出 'close' 事件。
server.getTicketKeys(): void- 返回:{Buffer} 包含会话票证密钥的 48 字节缓冲区。
返回会话票证密钥。
有关更多信息,请参阅 会话恢复。
server.listen(): void启动服务器监听加密连接。
此方法与 net.Server 中的 server.listen() 相同。
server.setSecureContext(options): void<Object>server.setSecureContext() 方法替换现有服务器的安全上下文。到服务器的现有连接不会中断。
server.setTicketKeys(keys): void<TypedArray>
|
<DataView>设置会话票证密钥。
票证密钥的更改仅对未来的服务器连接有效。现有或当前待处理的服务器连接将使用以前的密钥。
有关更多信息,请参阅 会话恢复。
类:tls.TLSSocket
History
- 继承自:
<net.Socket>
执行写入数据的透明加密和所有所需的 TLS 协商。
tls.TLSSocket 的实例实现了双工 [Stream][] 接口。
返回 TLS 连接元数据的方法(例如 tls.TLSSocket.getPeerCertificate())仅在连接打开时返回数据。
new tls.TLSSocket(socket, options?): void<net.Socket>
|
<stream.Duplex><Object>true
,TLS socket 将实例化为服务器。
默认值:
false
。<net.Server>net.Server
实例。isServer
为 true)可以将
requestCert
设置为 true 以请求客户端证书。Buffer
实例。<boolean>true
,指定 OCSP 状态请求扩展将添加到客户端 hello 中,并且在建立安全通信之前将在 socket 上发出
'OCSPResponse'
事件tls.createSecureContext()
创建的 TLS 上下文对象。如果_未_提供
secureContext
,则将把整个
options
对象传递给
tls.createSecureContext()
来创建一个。secureContext
选项,则使用
tls.createSecureContext()
选项。否则,它们将被忽略。从现有的 TCP socket 构造一个新的 tls.TLSSocket 对象。
事件:'keylog'
History
line{Buffer} 一行 ASCII 文本,采用 NSSSSLKEYLOGFILE格式。
当 socket 生成或接收密钥材料时,会在 tls.TLSSocket 上发出 keylog 事件。此密钥材料可以存储用于调试,因为它允许解密捕获的 TLS 流量。它可能会发出多次,在握手完成之前或之后。
一个典型的用例是将接收到的行追加到一个公共文本文件中,该软件(例如 Wireshark)稍后使用该文件来解密流量:
const logFile = fs.createWriteStream('/tmp/ssl-keys.log', { flags: 'a' });
// ...
tlsSocket.on('keylog', (line) => logFile.write(line));事件:'OCSPResponse'
History
如果在创建 tls.TLSSocket 时设置了 requestOCSP 选项并且收到了 OCSP 响应,则会发出 'OCSPResponse' 事件。调用监听器回调时传入单个参数:
response{Buffer} 服务器的 OCSP 响应
通常,response 是来自服务器 CA 的数字签名对象,其中包含有关服务器证书吊销状态的信息。
事件:'secure'
History
'secure' 事件在 TLS 握手成功完成并建立安全连接后发出。
此事件在客户端和服务器 <tls.TLSSocket> 实例上发出,包括使用 new tls.TLSSocket() 构造函数创建的 socket。
事件:'secureConnect'
History
'secureConnect' 事件在新连接的握手过程成功完成后发出。无论服务器的证书是否已授权,都将调用监听器回调。客户端有责任检查 tlsSocket.authorized 属性以确定服务器证书是否由指定的 CA 之一签名。如果 tlsSocket.authorized === false,则可以通过检查 tlsSocket.authorizationError 属性找到错误。如果使用了 ALPN,则可以检查 tlsSocket.alpnProtocol 属性以确定协商的协议。
当使用 new tls.TLSSocket() 构造函数创建 <tls.TLSSocket> 时,不会发出 'secureConnect' 事件。
事件:'session'
History
session{Buffer}
当新会话或 TLS 票据可用时,会在客户端 tls.TLSSocket 上发出 'session' 事件。这可能发生在握手完成之前或之后,具体取决于协商的 TLS 协议版本。该事件不在服务器上发出,或者如果没有创建新会话,例如当连接恢复时。对于某些 TLS 协议版本,该事件可能会发出多次,在这种情况下,所有会话都可用于恢复。
在客户端,session 可以提供给 tls.connect() 的 session 选项以恢复连接。
参见 会话恢复 获取更多信息。
对于 TLSv1.2 及以下版本,一旦握手完成,可以调用 tls.TLSSocket.getSession()。对于 TLSv1.3,协议仅允许基于票据的恢复,发送多个票据,并且票据仅在握手完成后发送。因此有必要等待 'session' 事件来获取可恢复的会话。应用程序应使用 'session' 事件而不是 getSession() 以确保它们适用于所有 TLS 版本。仅期望获取或使用一个会话的应用程序应只监听此事件一次:
tlsSocket.once('session', (session) => {
// 会话可以立即使用或稍后使用。
tls.connect({
session: session,
// 其他连接选项...
});
});tlsSocket.address(): void- 返回:
<Object>
返回操作系统报告的底层 socket 的绑定 address、地址 family 名称和 port:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }。
返回对等方证书未被验证的原因。此属性仅在 tlsSocket.authorized === false 时设置。
- 类型:
<boolean>
如果对等证书由创建 tls.TLSSocket 实例时指定的 CA 之一签名,则此属性为 true,否则为 false。
tlsSocket.disableRenegotiation(): void禁用此 TLSSocket 实例的 TLS 重新协商。一旦调用,尝试重新协商将触发 TLSSocket 上的 'error' 事件。
tlsSocket.enableTrace(): void启用后,TLS 数据包跟踪信息将写入 stderr。这可用于调试 TLS 连接问题。
输出格式与 openssl s_client -trace 或 openssl s_server -trace 的输出相同。虽然它是由 OpenSSL 的 SSL_trace() 函数生成的,但格式未记录在案,可能会在不通知的情况下更改,不应依赖。
始终返回 true。这可用于区分 TLS socket 和普通的 net.Socket 实例。
tlsSocket.exportKeyingMaterial(length, label, context?): void<number><string>密钥材料用于验证以防止网络协议中的不同类型的攻击,例如在 IEEE 802.1X 的规范中。
示例
const keyingMaterial = tlsSocket.exportKeyingMaterial(
128,
'client finished');
/*
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 更多字节>
*/参见 OpenSSL SSL_export_keying_material 文档获取更多信息。
tlsSocket.getCertificate(): void- 返回:
<Object>
返回一个代表本地证书的对象。返回的对象具有对应于证书字段的一些属性。
参见 tls.TLSSocket.getPeerCertificate() 获取证书结构示例。
如果没有本地证书,将返回一个空对象。如果 socket 已被销毁,将返回 null。
tlsSocket.getCipher
History
将 IETF 加密套件名称作为 standardName 返回。
返回最低加密套件版本,而不是固定字符串 ('TLSv1/SSLv3')。
tlsSocket.getCipher(): void- 返回:
<Object>Attributesname:<string>加密套件的 OpenSSL 名称。standardName:<string>加密套件的 IETF 名称。version:<string>此加密套件支持的最低 TLS 协议版本。对于实际协商的协议,参见tls.TLSSocket.getProtocol()。
返回一个包含有关协商加密套件信息的对象。
例如,带有 AES256-SHA 加密的 TLSv1.2 协议:
{
"name": "AES256-SHA",
"standardName": "TLS_RSA_WITH_AES_256_CBC_SHA",
"version": "SSLv3"
}参见 SSL_CIPHER_get_name 获取更多信息。
tlsSocket.getEphemeralKeyInfo(): void- 返回:
<Object>
返回一个对象,表示客户端连接上 完美前向保密 中临时密钥交换的类型、名称和参数大小。当密钥交换不是临时的,它返回一个空对象。由于这仅在客户端 socket 上支持;如果在服务器 socket 上调用,则返回 null。支持的类型是 'DH' 和 'ECDH'。name 属性仅在类型为 'ECDH' 时可用。
例如:{ type: 'ECDH', name: 'prime256v1', size: 256 }。
tlsSocket.getFinished(): void- 返回:
<undefined>最新的Finished消息,已作为 SSL/TLS 握手的一部分发送到 socket,或者如果尚未发送Finished消息则为undefined。
由于 Finished 消息是完整握手的信息摘要(TLS 1.0 总共 192 位,SSL 3.0 更多),当 SSL/TLS 提供的认证不需要或不够时,它们可用于外部认证过程。
对应于 OpenSSL 中的 SSL_get_finished 例程,并可用于实现 RFC 5929 中的 tls-unique 通道绑定。
tlsSocket.getPeerCertificate(detailed?): void返回一个代表对等方证书的对象。如果对等方未提供证书,将返回一个空对象。如果 socket 已被销毁,将返回 null。
如果请求了完整证书链,每个证书将包含一个 issuerCertificate 属性,其中包含一个代表其颁发者证书的对象。
证书对象具有对应于证书字段的属性。
<boolean>true
,否则为
false
。<Object>C
)、州或省 (
ST
)、 locality (
L
)、组织 (
O
)、组织单位 (
OU
) 和通用名称 (
CN
) 来描述。通用名称通常是 TLS 证书的 DNS 名称。示例:
{C: 'UK', ST: 'BC', L: 'Metro', O: 'Node Fans', OU: 'Docs', CN: 'example.com'}
。<Object>subject
相同。<string><string><string>'B9B0D332A1AA5635'
。<string>:
分隔的十六进制字符串返回。示例:
'2A:7A:C2:DD:...'
。<string>:
分隔的十六进制字符串返回。示例:
'2A:7A:C2:DD:...'
。<string>:
分隔的十六进制字符串返回。示例:
'2A:7A:C2:DD:...'
。<Array><string>subject
名称的替代方案。<Array><Object>证书可能包含有关公钥的信息,具体取决于密钥类型。
对于 RSA 密钥,可以定义以下属性:
对于 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(): void- 返回:
<undefined>最新的Finished消息,预期或已实际作为 SSL/TLS 握手的一部分从 socket 接收,或者如果到目前为止没有Finished消息则为undefined。
由于 Finished 消息是完整握手的信息摘要(TLS 1.0 总共 192 位,SSL 3.0 更多),当 SSL/TLS 提供的认证不需要或不够时,它们可用于外部认证过程。
对应于 OpenSSL 中的 SSL_get_peer_finished 例程,并可用于实现 RFC 5929 中的 tls-unique 通道绑定。
tlsSocket.getPeerX509Certificate(): void- 返回:{X509Certificate}
返回对等证书作为 {X509Certificate} 对象。
如果没有对等证书,或者 socket 已被销毁,将返回 undefined。
tlsSocket.getProtocol(): void返回一个包含当前连接协商的 SSL/TLS 协议版本的字符串。对于尚未完成握手过程的连接 socket,将返回值 'unknown'。对于服务器 socket 或断开的客户端 socket,将返回值 null。
协议版本有:
'SSLv3''TLSv1''TLSv1.1''TLSv1.2''TLSv1.3'
参见 OpenSSL SSL_get_version 文档获取更多信息。
tlsSocket.getSession(): void- 类型:{Buffer}
返回 TLS 会话数据,如果没有协商会话则返回 undefined。在客户端,数据可以提供给 tls.connect() 的 session 选项以恢复连接。在服务器上,它可能用于调试。
参见 会话恢复 获取更多信息。
注意:getSession() 仅适用于 TLSv1.2 及以下版本。对于 TLSv1.3,应用程序必须使用 'session' 事件(它也适用于 TLSv1.2 及以下版本)。
tlsSocket.getSharedSigalgs(): void- 返回:
<Array>服务器和客户端之间共享的签名算法列表,按偏好递减顺序排列。
参见 SSL_get_shared_sigalgs 获取更多信息。
tlsSocket.getTLSTicket(): void- 类型:{Buffer}
对于客户端,如果可用则返回 TLS 会话票据,否则返回 undefined。对于服务器,始终返回 undefined。
它可能用于调试。
参见 会话恢复 获取更多信息。
tlsSocket.getX509Certificate(): void- 返回:{X509Certificate}
返回本地证书作为 {X509Certificate} 对象。
如果没有本地证书,或者 socket 已被销毁,将返回 undefined。
tlsSocket.isSessionReused(): void- 返回:
<boolean>如果会话被重用则为true,否则为false。
参见 会话恢复 获取更多信息。
- 类型:
<string>
返回本地 IP 地址的字符串表示。
- 类型:
<integer>
返回本地端口的数字表示。
- 类型:
<string>
返回远程 IP 地址的字符串表示。例如,'74.125.127.100' 或 '2001:4860:a005::68'。
- 类型:
<string>
返回远程 IP 家族的字符串表示。'IPv4' 或 'IPv6'。
- 类型:
<integer>
返回远程端口的数字表示。例如,443。
tlsSocket.renegotiate
History
向 callback 参数传递无效的回调现在抛出 ERR_INVALID_ARG_TYPE 而不是ERR_INVALID_CALLBACK。
tlsSocket.renegotiate(options, callback): void<Object><boolean>false
,则根据提供的 CA 列表验证服务器证书。如果验证失败则发出
'error'
事件;
err.code
包含 OpenSSL 错误代码。
默认值:
true
。<Function>renegotiate()
返回
true
,回调 once 附加到
'secure'
事件。如果
renegotiate()
返回
false
,
callback
将在下一个 tick 中被调用并带有错误,除非
tlsSocket
已被销毁,在这种情况下
callback
将根本不会被调用。tlsSocket.renegotiate() 方法启动 TLS 重新协商过程。完成后,callback 函数将传入单个参数,该参数是 Error(如果请求失败)或 null。
此方法可用于在建立安全连接后请求对等方的证书。
当作为服务器运行时,socket 将在 handshakeTimeout 超时后被销毁并报错。
对于 TLSv1.3,无法启动重新协商,协议不支持。
tlsSocket.setKeyCert(context): void<Object>
|
<tls.SecureContext>tls.createSecureContext()
options
的至少
key
和
cert
属性,或使用
tls.createSecureContext()
本身创建的 TLS 上下文对象。tlsSocket.setKeyCert() 方法设置用于 socket 的私钥和证书。这主要有用,如果您希望从 TLS 服务器的 ALPNCallback 中选择服务器证书。
tlsSocket.setMaxSendFragment(size): voidtlsSocket.setMaxSendFragment() 方法设置最大 TLS 分片大小。如果设置限制成功则返回 true;否则返回 false。
较小的分片大小减少客户端上的缓冲延迟:较大的分片由 TLS 层缓冲,直到收到整个分片并验证其完整性;较大的分片可以跨越多个往返,并且由于数据包丢失或重新排序,它们的处理可能会延迟。然而,较小的分片增加额外的 TLS framing 字节和 CPU 开销,这可能会降低整体服务器吞吐量。
tls.checkServerIdentity(hostname, cert): void验证证书 cert 是否颁发给 hostname。
返回 <Error> 对象,失败时使用 reason、host 和 cert 填充它。成功时返回 <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
History
添加了 onread 选项。
现在接受 highWaterMark 选项。
现在支持 pskCallback 选项。
支持 allowHalfOpen 选项。
现在支持 hints 选项。
现在支持 enableTrace 选项。
现在支持 timeout 选项。
现在支持 lookup 选项。
ALPNProtocols 选项现在可以是 TypedArray 或 DataView。
现在支持 secureContext 选项。
现在支持 ALPN 选项。
tls.connect(options, callback?): void<Object><string>'localhost'
。<number><string>host
和
port
将被忽略。<stream.Duplex>net.Socket
的实例,但允许任何
Duplex
流。
如果指定了此选项,
path
、
host
和
port
将被忽略,证书验证除外。通常,传递给
tls.connect()
时套接字已经连接,但也可以稍后连接。
socket
的连接/断开/销毁由用户负责;调用
tls.connect()
不会导致调用
net.connect()
。<boolean>false
,则当可读端结束时,套接字将自动结束可写端。如果设置了
socket
选项,则此选项无效。详见
net.Socket
的
allowHalfOpen
选项。
默认:
false
。<boolean>false
,则将根据提供的 CA 列表验证服务器证书。如果验证失败,将发出
'error'
事件;
err.code
包含 OpenSSL 错误代码。
默认:
true
。<Function><string[]>
|
<TypedArray>
|
<DataView>Buffer
、
TypedArray
或
DataView
。缓冲区应具有格式
[len][name][len][name]...
,例如
'\x08http/1.1\x08http/1.0'
,其中
len
字节是下一个协议名称的长度。传递数组通常更简单,例如
['http/1.1', 'http/1.0']
。列表中较早的协议比较后的协议具有更高的优先级。<string>tls.createServer()
的
SNICallback
选项。<Function>servername
)时使用的回调函数(代替内置的
tls.checkServerIdentity()
函数)。如果验证失败,这应返回一个
<Error>
。如果
servername
和
cert
已验证,该方法应返回
undefined
。Buffer
实例,包含 TLS 会话。<boolean>true
,指定 OCSP 状态请求扩展将添加到客户端问候中,并且在建立安全通信之前将在套接字上发出
'OCSPResponse'
事件。<number>minDHSize
时,TLS 连接将被销毁并抛出错误。
默认:
1024
。<number>highWaterMark
参数一致。
默认:
16 * 1024
。<number>
如果设置且内部创建了套接字,将在套接字创建后但在开始连接之前调用
socket.setTimeout(timeout)
。tls.createSecureContext()
创建的 TLS 上下文对象。如果_未_提供
secureContext
,将通过将整个
options
对象传递给
tls.createSecureContext()
来创建一个。<Object>secureContext
选项则使用的
tls.createSecureContext()
选项,否则它们将被忽略。socket.connect()
选项。<Function><tls.TLSSocket>如果指定了 callback 函数,它将作为 'secureConnect' 事件的监听器添加。
tls.connect() 返回一个 tls.TLSSocket 对象。
与 https API 不同,tls.connect() 默认不启用 SNI(服务器名称指示)扩展,这可能导致某些服务器返回错误的证书或完全拒绝连接。要启用 SNI,除了 host 外,还需设置 servername 选项。
以下说明了 tls.createServer() 中回显服务器示例的客户端:
// 假设有一个监听端口 8000 的回显服务器。
import { connect } from 'node:tls';
import { readFileSync } from 'node:fs';
import { stdin } from 'node:process';
const options = {
// 仅当服务器需要客户端证书认证时才必要。
key: readFileSync('client-key.pem'),
cert: readFileSync('client-cert.pem'),
// 仅当服务器使用自签名证书时才必要。
ca: [ readFileSync('server-cert.pem') ],
// 仅当服务器的证书不是用于 "localhost" 时才必要。
checkServerIdentity: () => { return null; },
};
const socket = connect(8000, options, () => {
console.log('client connected',
socket.authorized ? 'authorized' : 'unauthorized');
stdin.pipe(socket);
stdin.resume();
});
socket.setEncoding('utf8');
socket.on('data', (data) => {
console.log(data);
});
socket.on('end', () => {
console.log('server ends connection');
});要生成此示例的证书和密钥,请运行:
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
-keyout client-key.pem -out client-cert.pem然后,要生成此示例的 server-cert.pem 证书,请运行:
openssl pkcs12 -certpbe AES-256-CBC -export -out server-cert.pem \
-inkey client-key.pem -in client-cert.pemtls.connect(path, options?, callback?): void<string>options.path
的默认值。<Object>tls.connect()
。<Function>tls.connect()
。<tls.TLSSocket>与 tls.connect() 相同,只不过 path 可以作为参数提供,而不是作为选项。
如果指定了 path 选项,它将优先于 path 参数。
tls.connect(port, host?, options?, callback?): void<number>options.port
的默认值。<string>options.host
的默认值。<Object>tls.connect()
。<Function>tls.connect()
。<tls.TLSSocket>与 tls.connect() 相同,只不过 port 和 host 可以作为参数提供,而不是作为选项。
如果指定了 port 或 host 选项,它将优先于任何 port 或 host 参数。
tls.createSecureContext
History
添加了 allowPartialTrustChain 选项。
clientCertEngine、privateKeyEngine 和privateKeyIdentifier 选项依赖于 OpenSSL 中的自定义引擎支持,该支持在 OpenSSL 3 中已废弃。
dhparam 选项现在可以设置为 'auto' 以启用具有适当知名参数的 DHE。
添加了 privateKeyIdentifier 和 privateKeyEngine 选项以从 OpenSSL 引擎获取私钥。
添加了 sigalgs 选项以覆盖支持的签名算法。
添加了 TLSv1.3 支持。
ca: 选项现在支持 BEGIN TRUSTED CERTIFICATE。
minVersion 和 maxVersion 可用于限制允许的 TLS 协议版本。
由于 OpenSSL 的变更,ecdhCurve 不再能设置为 false。
options 参数现在可以包含 clientCertEngine。
ecdhCurve 选项现在可以是多个由 ':' 分隔的曲线名称或 'auto'。
如果 key 选项是一个数组,单个条目不再需要 passphrase 属性。Array 条目现在也可以只是 string 或 Buffer。
ca 选项现在可以是包含多个 CA 证书的单个字符串。
tls.createSecureContext(options?): void<Object><boolean><string>
|
<string[]>default
类型通过
tls.getCACertificates()
返回的证书相同。如果指定,默认列表将被
ca
选项中的证书完全替换(而不是连接)。如果用户希望添加额外的证书而不是完全覆盖默认值,则需要手动连接。
值可以是字符串或
Buffer
,或者是字符串和/或
Buffer
的
Array
。任何字符串或
Buffer
都可以包含多个连接在一起的 PEM CA。对等方的证书必须能够链接到服务器信任的 CA 才能对连接进行身份验证。当使用无法链接到知名 CA 的证书时,必须明确指定证书的 CA 为受信任,否则连接将无法通过身份验证。
如果对等方使用的证书与默认 CA 之一不匹配或无法链接到其中之一,请使用
ca
选项提供对等方证书可以匹配或链接到的 CA 证书。
对于自签名证书,证书是其自身的 CA,必须提供。
对于 PEM 编码的证书,支持的类型是 "TRUSTED CERTIFICATE"、"X509 CERTIFICATE" 和 "CERTIFICATE"。<string>
|
<string[]>key
的 PEM 格式证书组成,后跟 PEM 格式的中间证书(如果有),按顺序排列,不包括根 CA(根 CA 必须为对等方预先知晓,参见
ca
)。当提供多个证书链时,它们的顺序不必与
key
中的私钥顺序相同。如果未提供中间证书,对等方将无法验证证书,握手将失败。<string>SHA256
、
MD5
等)、公钥算法(
RSA-PSS
、
ECDSA
等)、两者的组合(例如 'RSA+SHA384')或 TLS v1.3 方案名称(例如
rsa_pss_pss_sha512
)。
请参阅
OpenSSL 手册页
以获取更多信息。<string>tls.getCiphers()
获取。为了使 OpenSSL 接受,密码名称必须大写。<string><string>
|
<string[]><string><string>P-521:P-384:P-256
,用于 ECDH 密钥协商。设置为
auto
以自动选择曲线。使用
crypto.getCurves()
获取可用曲线名称列表。在最近版本中,
openssl ecparam -list_curves
也将显示每个可用椭圆曲线的名称和描述。
默认值:
tls.DEFAULT_ECDH_CURVE
。<boolean>true
时,会导致在
secureOptions
中设置
SSL_OP_CIPHER_SERVER_PREFERENCE
,请参阅
OpenSSL 选项
以获取更多信息。<string>
|
<string[]>
|
<Object[]>options.passphrase
解密。可以使用不同算法的多个密钥,既可以作为未加密密钥字符串或缓冲区的数组提供,也可以作为
{pem: <string|buffer>[, passphrase: <string>]}
形式的对象数组提供。对象形式只能出现在数组中。
object.passphrase
是可选的。如果提供了加密密钥,将使用
object.passphrase
解密,否则使用
options.passphrase
。<string>privateKeyIdentifier
一起使用。
已废弃。<string>privateKeyEngine
一起使用。不应与
key
一起设置,因为这两个选项以不同方式定义私钥。
已废弃。<string>'TLSv1.3'
、
'TLSv1.2'
、
'TLSv1.1'
或
'TLSv1'
之一。不能与
secureProtocol
选项一起指定;请使用其中之一。
默认值:
tls.DEFAULT_MAX_VERSION
。<string>'TLSv1.3'
、
'TLSv1.2'
、
'TLSv1.1'
或
'TLSv1'
之一。不能与
secureProtocol
选项一起指定;请使用其中之一。避免设置为低于 TLSv1.2,但为了互操作性可能需要。TLSv1.2 之前的版本可能需要降低
OpenSSL 安全级别
。
默认值:
tls.DEFAULT_MIN_VERSION
。<string><string>
|
<string[]>
|
<Object[]>pfx
是单独提供
key
和
cert
的替代方案。PFX 通常是加密的,如果是,
passphrase
将用于解密它。可以提供多个 PFX,既可以作为未加密 PFX 缓冲区的数组,也可以作为
{buf: <string|buffer>[, passphrase: <string>]}
形式的对象数组。对象形式只能出现在数组中。
object.passphrase
是可选的。如果提供了加密 PFX,将使用
object.passphrase
解密,否则使用
options.passphrase
。<number>SSL_OP_*
选项的数字位掩码。<string>minVersion
和
maxVersion
。可能的值列为
SSL_METHODS
,使用函数名作为字符串。例如,使用
'TLSv1_1_method'
强制 TLS 版本 1.1,或使用
'TLS_method'
允许任何高达 TLSv1.3 的 TLS 协议版本。不建议使用低于 1.2 的 TLS 版本,但为了互操作性可能需要。
默认值:
无,参见
minVersion
。<string>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 选项。
使用证书的密码 需要 密钥。可以使用 key 或 pfx 来提供它。
如果未给出 ca 选项,则 Node.js 将默认使用 [Mozilla 公开信任的 CA 列表][]。
不鼓励使用自定义 DHE 参数,而是使用新的 dhparam: 'auto' 选项。当设置为 'auto' 时,将自动选择具有足够强度的知名 DHE 参数。否则,如有必要,可以使用 openssl dhparam 创建自定义参数。密钥长度必须大于或等于 1024 位,否则将抛出错误。虽然 1024 位是允许的,但为了更强的安全性,请使用 2048 位或更大。
tls.createServer
History
clientCertEngine 选项依赖于 OpenSSL 中的自定义引擎支持,该支持在 OpenSSL 3 中已弃用。
options 参数现在可以包含 ALPNCallback。
如果设置了 ALPNProtocols,发送不含支持协议的ALPN 扩展的传入连接将被终止,并返回致命的 no_application_protocol 警报。
options 参数现在支持 net.createServer()选项。
options 参数现在可以包含 clientCertEngine。
ALPNProtocols 选项现在可以是 TypedArray 或DataView。
现在支持 ALPN 选项。
tls.createServer(options?, secureConnectionListener?): void<Object><string[]>
|
<TypedArray>
|
<DataView>Buffer
、
TypedArray
或
DataView
,包含支持的
ALPN 协议。Buffer 的格式应为
[len][name][len][name]...
,
例如
0x05hello0x05world
,其中第一个字节是下一个
协议名称的长度。传递数组通常更简单,例如
['hello', 'world']
。(协议应按其优先级排序。)<Function>servername
和
protocols
字段的对象,分别包含来自
SNI 扩展的服务器名称(如果有)和 ALPN 协议名称字符串数组。
回调必须返回
protocols
中列出的字符串之一,该字符串将作为选定的
ALPN 协议返回给客户端,或者返回
undefined
以拒绝连接并发出致命警报。
如果返回的字符串与客户端的 ALPN
协议之一不匹配,将抛出错误。此选项不能与
ALPNProtocols
选项一起使用,同时设置这两个选项将抛出错误。<string><boolean><number>tls.Server
对象上都会发出
'tlsClientError'
。
默认:
120000
(120 秒)。<boolean>false
,服务器将拒绝任何
未使用提供的 CA 列表授权的任何连接。此
选项仅在
requestCert
为
true
时有效。
默认:
true
。<boolean>true
,服务器将请求来自
连接的客户端的证书并尝试验证该证书。
默认:
false
。<Function>servername
和
callback
。
callback
是一个
错误优先的回调,接受两个可选参数:
error
和
ctx
。
如果提供了
ctx
,它是一个
SecureContext
实例。
tls.createSecureContext()
可用于获取适当的
SecureContext
。
如果用假值
ctx
参数调用
callback
,将使用服务器的默认安全
上下文。如果未提供
SNICallback
,将使用带有高级 API 的默认
回调(见下文)。<Function><string>'tlsClientError'
,代码为
'ERR_TLS_PSK_SET_IDENTITY_HINT_FAILED'
。net.createServer()
选项。<Function><tls.Server>创建一个新的 tls.Server。如果提供了 secureConnectionListener,它
会自动设置为 'secureConnection' 事件的监听器。
ticketKeys 选项会在 node:cluster 模块
工作进程之间自动共享。
以下说明了一个简单的回显服务器:
import { createServer } from 'node:tls';
import { readFileSync } from 'node:fs';
const options = {
key: readFileSync('server-key.pem'),
cert: readFileSync('server-cert.pem'),
// 仅在使用客户端证书认证时才需要此项。
requestCert: true,
// 仅当客户端使用自签名证书时才需要此项。
ca: [ readFileSync('client-cert.pem') ],
};
const server = 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');
});要为生成此示例的证书和密钥,运行:
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
-keyout server-key.pem -out server-cert.pem然后,要为此示例生成 client-cert.pem 证书,运行:
openssl pkcs12 -certpbe AES-256-CBC -export -out client-cert.pem \
-inkey server-key.pem -in server-cert.pem可以使用来自 tls.connect() 的示例客户端连接到此服务器来进行测试。
tls.setDefaultCACertificates(certs): void<string[]>设置 Node.js TLS 客户端使用的默认 CA 证书。如果提供的
证书解析成功,它们将成为 tls.getCACertificates() 返回的默认 CA
证书列表,并由后续未指定自己 CA 证书的 TLS 连接使用。
在设置为默认值之前,证书将被去重。
此函数仅影响当前 Node.js 线程。HTTPS 代理缓存的先前 会话不会受此更改影响,因此 应在进行任何不需要的可缓存 TLS 连接之前调用此方法。
要将系统 CA 证书用作默认值:
const tls = require('node:tls');
tls.setDefaultCACertificates(tls.getCACertificates('system'));此函数完全替换默认的 CA 证书列表。要将其他 证书添加到现有默认值中,获取当前证书并追加它们:
const tls = require('node:tls');
const currentCerts = tls.getCACertificates('default');
const additionalCerts = ['-----BEGIN CERTIFICATE-----\n...'];
tls.setDefaultCACertificates([...currentCerts, ...additionalCerts]);tls.getCACertificates(type?): void<string>
|
<undefined>"default"
、
"system"
、
"bundled"
和
"extra"
。
默认:
"default"
。<string[]>
PEM 编码证书的数组。如果同一证书在多个来源中重复存储,数组可能包含重复项。返回一个包含来自各种来源的 CA 证书的数组,具体取决于 type:
"default":返回 Node.js TLS 客户端默认使用的 CA 证书。- 当启用
--use-bundled-ca(默认)或未启用--use-openssl-ca时, 这将包括来自捆绑的 Mozilla CA 存储的 CA 证书。 - 当启用
--use-system-ca时,这还将包括来自系统 信任存储的证书。 - 当使用
NODE_EXTRA_CA_CERTS时,这还将包括从指定 文件加载的证书。
- 当启用
"system":返回根据--use-system-ca设置的规则从系统信任存储加载的 CA 证书。 当未启用--use-system-ca时,这可用于获取系统证书。"bundled":返回来自捆绑的 Mozilla CA 存储的 CA 证书。这与tls.rootCertificates相同。"extra":返回从NODE_EXTRA_CA_CERTS加载的 CA 证书。如果 未设置NODE_EXTRA_CA_CERTS,则为空数组。
tls.getCiphers(): void- 返回值:
<string[]>
返回一个数组,包含支持的 TLS 加密套件的名称。出于历史原因,这些名称是小写的,但在 tls.createSecureContext() 的 ciphers 选项中使用必须大写。
并非所有支持的加密套件默认都是启用的。请参阅 修改默认 TLS 加密套件。
以 'tls_' 开头的加密套件名称用于 TLSv1.3,所有其他名称用于 TLSv1.2 及以下版本。
console.log(tls.getCiphers()); // ['aes128-gcm-sha256', 'aes128-sha', ...]- 类型:
<string[]>
一个不可变的字符串数组,表示当前 Node.js 版本提供的捆绑 Mozilla CA 存储中的根证书(PEM 格式)。
Node.js 提供的捆绑 CA 存储是发布时固定的 Mozilla CA 存储的快照。它在所有支持的平台上都是相同的。
要获取当前 Node.js 实例实际使用的 CA 证书(可能包括从系统存储加载的证书(如果使用了 --use-system-ca)或从 NODE_EXTRA_CA_CERTS 指示的文件加载的证书),请使用 tls.getCACertificates()。
TLS 服务器中用于 ECDH 密钥协商的默认曲线名称。默认值为 'auto'。有关更多信息,请参阅 tls.createSecureContext()。
- 类型:
<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'。如果提供了多个选项,则使用最高的最大值。
- 类型:
<string>tls.createSecureContext()的minVersion选项的默认值。它可以被赋值为任何支持的 TLS 协议版本,'TLSv1.3'、'TLSv1.2'、'TLSv1.1'或'TLSv1'。 TLSv1.2 之前的版本可能需要降低 OpenSSL 安全级别。 默认值:'TLSv1.2',除非使用 CLI 选项更改。使用--tls-min-v1.0将默认值设置为'TLSv1'。使用--tls-min-v1.1将默认值设置为'TLSv1.1'。使用--tls-min-v1.3将默认值设置为'TLSv1.3'。如果提供了多个选项,则使用最低的最低值。
- 类型:
<string>tls.createSecureContext()的ciphers选项的默认值。它可以被赋值为任何支持的 OpenSSL 加密套件。默认为crypto.constants.defaultCoreCipherList的内容,除非使用--tls-default-ciphersCLI 选项更改。