ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# TLS (SSL) ~~~ 稳定度: 3 - 稳定 ~~~ 使用 `require('tls')` 来访问此模块。 `tls` 模块使用 OpenSSL 来提供传输层安全协议(Transport Layer Security)和/或安全套接层(Secure Socket Layer):加密过的流通讯。 TLS/SSL 是一种公钥/私钥架构。每个客户端和服务器都必有一个私钥。一个私钥使用类似的方式创建: ~~~ openssl genrsa -out ryans-key.pem 1024 ~~~ 所有服务器和某些客户端需要具备证书。证书是证书办法机构签发或自签发的公钥。获取证书的第一步是创建一个“证书签发申请”(CSR)文件。使用这条命令完成: ~~~ openssl req -new -key ryans-key.pem -out ryans-csr.pem ~~~ 像这样使用 CSR 创建一个自签名证书: ~~~ openssl x509 -req -in ryans-csr.pem -signkey ryans-key.pem -out ryans-cert.pem ~~~ 又或者你可以将 CSR 发送给一个数字证书认证机构请求签名。 (TODO: 对于创建一个CA文档, 感兴趣的用户暂时只能看Node的源代码`test/fixtures/keys/Makefile` 像这样创建 .pfx 或 .p12: ~~~ openssl pkcs12 -export -in agent5-cert.pem -inkey agent5-key.pem \ -certfile ca-cert.pem -out agent5.pfx ~~~ - `in`: certificate - `inkey`: private key - `certfile`: all CA certs concatenated in one file like `cat ca1-cert.pem ca2-cert.pem > ca-cert.pem` ### 客户端初始化的对缓解攻击的重新协商 TLS协议会令客户端可以重新协商TLS会话的某些方面。但是,会话的重新协商是需要相应量的服务器端资源的,所以导致其变成一个阻断服务攻击(denial-of-service)的潜在媒介。 为了减低这种情况的发生,重新协商被限制在每10分钟三次。如果超过这个数目,那么在[tls.TLSSocket](#)实例上就会分发一个错误。这个限制是可设置的: - `tls.CLIENT_RENEG_LIMIT`: 重新协商的次数限制,默认为3。 - `tls.CLIENT_RENEG_WINDOW`: 重新协商窗口的秒数,默认为600(10分钟)。 除非你完全理解整个机制和清楚自己要干什么,否则不要改变这个默认值。 要测试你的服务器的话,用命令 `openssl s_client -connect 地址:端口`连接上服务器,然后敲击`R<CR>`(字母键`R`加回车键)几次。 ### NPN 和 SNI NPN (Next Protocol Negotiation,下一个协议的协商)和SNI (Server Name Indication,服务器名称指示)是TLS握手扩展,它们允许你: - NPN - 同一个TLS服务器使用多种协议 (HTTP, SPDY) - SNI - 同一个TLS服务器使用多个主机名,与其相应的SSL证书。 ### tls.getCiphers() 返回一个数组,其中包含了所支持的SSL加密器的名字。 实例: ~~~ var ciphers = tls.getCiphers(); console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...] ~~~ ### tls.createServer(options, [secureConnectionListener]) 新建一个新的 [tls.Server](#). The `connectionListener` 参数会自动设置为 [secureConnection](#) 事件的监听器. 这个 `options` 对象有这些可能性: - `pfx`: 一个String 或`Buffer`包含了私钥, 证书和CA certs, 一般是 PFX 或者 PKCS12 格式. (Mutually exclusive with the `key`, `cert` and `ca` options.) - `key`: 一个字符串或 `Buffer`对象,其中包含了PEF格式的服务器的私钥。 (必需) - `passphrase`: 私钥或pfx密码的字符串。 - `cert`: 字符串或者 `Buffer`,包含PEM格式的服务器证书密码。(必选) - `ca`: An array of strings or `Buffer`s of trusted certificates. If this is omitted several well known "root" CAs will be used, like VeriSign. These are used to authorize connections. - `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) - `ciphers`: 一个字符串,描述了使用或排除的cipher。 ~~~ **NOTE**: Previous revisions of this section suggested `AES256-SHA` as an acceptable cipher. Unfortunately, `AES256-SHA` is a CBC cipher and therefore susceptible to BEAST attacks. Do *not* use it. ~~~ - `handshakeTimeout`: Abort the connection if the SSL/TLS handshake does not finish in this many milliseconds. The default is 120 seconds. ~~~ `tls.Server`对象在握手超时时,总会触发`'clientError'`事件。 ~~~ - `honorCipherOrder` : 当选择cipher时,使用服务器设置,而不是客户端设置。 ~~~ Although, this option is disabled by default, it is *recommended* that you use this option in conjunction with the `ciphers` option to mitigate BEAST attacks. ~~~ - `requestCert`: If `true` the server will request a certificate from clients that connect and attempt to verify that certificate. Default: `false`. - `rejectUnauthorized`: If `true` the server will reject any connection which is not authorized with the list of supplied CAs. This option only has an effect if `requestCert` is `true`. Default: `false`. - `NPNProtocols`: 一个数组或 `Buffer`,包含了可能的 NPN 协议。(协议应根据优先级排序) - `SNICallback(servername, cb)`: A function that will be called if client supports SNI TLS extension. Two argument will be passed to it: `servername`, and `cb`. `SNICallback` should invoke `cb(null, ctx)`, where `ctx` is a SecureContext instance. (You can use `crypto.createCredentials(...).context` to get proper SecureContext). If `SNICallback` wasn't provided - default callback with high-level API will be used (see below). - `sessionTimeout`: An integer specifying the seconds after which TLS session identifiers and TLS session tickets created by the server are timed out. See [SSL_CTX_set_timeout](http://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html) for more details. - `sessionIdContext`: A string containing a opaque identifier for session resumption. If `requestCert` is `true`, the default is MD5 hash value generated from command-line. Otherwise, the default is not provided. - `secureProtocol`: The SSL method to use, e.g. `SSLv3_method` to force SSL version 3. The possible values depend on your installation of OpenSSL and are defined in the constant [SSL_METHODS](http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_PROTOCOL_METHODS). 这是一个简单的应答服务器例子: ~~~ var server = tls.createServer(options, function(socket) { console.log('服务器已连接', socket.authorized ? '已授权' : '未授权'); socket.write("欢迎!\n"); socket.setEncoding('utf8'); socket.pipe(socket); }); server.listen(8000, function() { console.log('server bound'); }); ~~~ 或者 ~~~ }; ~~~ ~~~ var server = tls.createServer(options, function(socket) { console.log('服务器已连接', socket.authorized ? '已授权' : '未授权'); socket.write("欢迎!\n"); socket.setEncoding('utf8'); socket.pipe(socket); }); server.listen(8000, function() { console.log('服务器已绑定'); }); ~~~ 您可以使用 `openssl s_client` 连接这个服务器来测试: ~~~ openssl s_client -connect 127.0.0.1:8000 ~~~ ### tls.connect(options, [callback]) ### tls.connect(port, [host], [options], [callback]) Creates a new client connection to the given `port` and `host` (old API) or `options.port` and `options.host`. (If `host` is omitted, it defaults to `localhost`.) `options` should be an object which specifies: - `host`: 客户端应连接到的主机 - `port`: 客户端应连接到的端口 - `socket`: Establish secure connection on a given socket rather than creating a new socket. If this option is specified, `host` and `port` are ignored. - `pfx`: 字符串或者 `Buffer`,包含 PFX 或 PKCS12 格式的服务器私钥、证书和CA证书。 - `key`: 字符串或 `Buffer`,包含 PEM 格式的客户端私钥。 - `passphrase`: 私钥或pfx密码的字符串。 - `cert`: 字符串或 `Buffer`,包含PEM格式的客户端证书密码。 - `ca`: An array of strings or `Buffer`s of trusted certificates. If this is omitted several well known "root" CAs will be used, like VeriSign. These are used to authorize connections. - `rejectUnauthorized`: If `true`, the server certificate is verified against the list of supplied CAs. An `'error'` event is emitted if verification fails. Default: `true`. - `NPNProtocols`: An array of string or `Buffer` containing supported NPN protocols. `Buffer` should have following format: `0x05hello0x05world`, where first byte is next protocol name's length. (Passing array should usually be much simpler: `['hello', 'world']`.) - `servername`: SNI (Server Name Indication) TLS 扩展的服务器名。 - `secureProtocol`: The SSL method to use, e.g. `SSLv3_method` to force SSL version 3. The possible values depend on your installation of OpenSSL and are defined in the constant [SSL_METHODS](http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_PROTOCOL_METHODS). `callback`参数会被作为监听器添加到['secureConnect'](#)事件。 `tls.connect()`返回一个[tls.TLSSocket](#)对象。 下面是一个上述应答服务器的客户端的例子: ~~~ var socket = tls.connect(8000, options, function() { console.log('client connected', socket.authorized ? 'authorized' : 'unauthorized'); process.stdin.pipe(socket); process.stdin.resume(); }); socket.setEncoding('utf8'); socket.on('data', function(data) { console.log(data); }); socket.on('end', function() { server.close(); }); ~~~ 或者 ~~~ var socket = tls.connect(8000, options, function() { console.log('client connected', socket.authorized ? 'authorized' : 'unauthorized'); process.stdin.pipe(socket); process.stdin.resume(); }); socket.setEncoding('utf8'); socket.on('data', function(data) { console.log(data); }); socket.on('end', function() { server.close(); }); ~~~ ### Class: tls.TLSSocket Wrapper for instance of [net.Socket](#), replaces internal socket read/write routines to perform transparent encryption/decryption of incoming/outgoing data. ### new tls.TLSSocket(socket, options) Construct a new TLSSocket object from existing TCP socket. `socket`是一个[net.Socket](#)示例。 `options`是一个可能包含以下属性的对象: - `credentials`: 可选的,通过`crypto.createCredentials( ... )`得到的资格对象。 - `isServer`: 如果为真——TLS套接字将在服务器模式下实例化。 - `server`: 一个可选的[net.Server](#)实例 - `requestCert`: 可选的,见[tls.createSecurePair](#) - `rejectUnauthorized`: 可选的,见[tls.createSecurePair](#) - `NPNProtocols`: 可选的,见[tls.createServer](#) - `SNICallback`: 可选的,见[tls.createServer](#) ### tls.createSecurePair([credentials], [isServer], [requestCert], [rejectUnauthorized]) ~~~ 稳定性: 0 - 已废弃。使用 tls.TLSSocket 替代。 ~~~ Creates a new secure pair object with two streams, one of which reads/writes encrypted data, and one reads/writes cleartext data. Generally the encrypted one is piped to/from an incoming encrypted data stream, and the cleartext one is used as a replacement for the initial encrypted stream. - `credentials`: 通过`crypto.createCredentials( ... )`得到的资格对象 - `isServer`: A boolean indicating whether this tls connection should be opened as a server or a client. - `requestCert`: A boolean indicating whether a server should request a certificate from a connecting client. Only applies to server connections. - `rejectUnauthorized`: A boolean indicating whether a server should automatically reject clients with invalid certificates. Only applies to servers with `requestCert` enabled. `tls.createSecurePair()` returns a SecurePair object with `cleartext` and `encrypted` stream properties. NOTE: `cleartext` has the same APIs as [tls.TLSSocket](#) ### 类: SecurePair 由tls.createSecurePair返回。 ### 事件: 'secure' The event is emitted from the SecurePair once the pair has successfully established a secure connection. Similarly to the checking for the server 'secureConnection' event, pair.cleartext.authorized should be checked to confirm whether the certificate used properly authorized. ### 类: tls.Server This class is a subclass of `net.Server` and has the same methods on it. Instead of accepting just raw TCP connections, this accepts encrypted connections using TLS or SSL. ### 事件: 'secureConnection' `function (tlsSocket) {}` This event is emitted after a new connection has been successfully handshaked. The argument is a instance of [tls.TLSSocket](#). It has all the common stream methods and events. `socket.authorized` is a boolean value which indicates if the client has verified by one of the supplied certificate authorities for the server. If `socket.authorized` is false, then `socket.authorizationError` is set to describe how authorization failed. Implied but worth mentioning: depending on the settings of the TLS server, you unauthorized connections may be accepted. `socket.npnProtocol` is a string containing selected NPN protocol. `socket.servername` is a string containing servername requested with SNI. ### Event: 'clientError' `function (exception, tlsSocket) { }` When a client connection emits an 'error' event before secure connection is established - it will be forwarded here. `tlsSocket`就是`[tls.TLSSocket][]`,错误产生的地方。 ### 事件: 'newSession' `function (sessionId, sessionData) { }` Emitted on creation of TLS session. May be used to store sessions in external storage. NOTE: adding this event listener will have an effect only on connections established after addition of event listener. ### 事件: 'resumeSession' `function (sessionId, callback) { }` Emitted when client wants to resume previous TLS session. Event listener may perform lookup in external storage using given `sessionId`, and invoke `callback(null, sessionData)` once finished. If session can't be resumed (i.e. doesn't exist in storage) one may call `callback(null, null)`. Calling `callback(err)` will terminate incoming connection and destroy socket. NOTE: adding this event listener will have an effect only on connections established after addition of event listener. ### server.listen(port, [host], [callback]) Begin accepting connections on the specified `port` and `host`. If the `host` is omitted, the server will accept connections directed to any IPv4 address (`INADDR_ANY`). This function is asynchronous. The last parameter `callback` will be called when the server has been bound. 更多信息见`net.Server`。 ### server.close() Stops the server from accepting new connections. This function is asynchronous, the server is finally closed when the server emits a `'close'` event. ### server.address() Returns the bound address, the address family name and port of the server as reported by the operating system. See [net.Server.address()](#) for more information. ### server.addContext(hostname, credentials) Add secure context that will be used if client request's SNI hostname is matching passed `hostname` (wildcards can be used). `credentials` can contain `key`, `cert` and `ca`. ### server.maxConnections Set this property to reject connections when the server's connection count gets high. ### server.connections 服务器的并发连接数. ### 类: CryptoStream ~~~ 稳定性: 0 - 已废弃。使用 tls.TLSSocket 替代。 ~~~ 这是一个被加密的流。 ### cryptoStream.bytesWritten A proxy to the underlying socket's bytesWritten accessor, this will return the total bytes written to the socket, *including the TLS overhead*. ### Class: tls.TLSSocket This is a wrapped version of [net.Socket](#) that does transparent encryption of written data and all required TLS negotiation. This instance implements a duplex [Stream](#) interfaces. It has all the common stream methods and events. ### 事件: 'secureConnect' This event is emitted after a new connection has been successfully handshaked. The listener will be called no matter if the server's certificate was authorized or not. It is up to the user to test `tlsSocket.authorized` to see if the server certificate was signed by one of the specified CAs. If `tlsSocket.authorized === false` then the error can be found in `tlsSocket.authorizationError`. Also if NPN was used - you can check `tlsSocket.npnProtocol` for negotiated protocol. ### tlsSocket.authorized A boolean that is `true` if the peer certificate was signed by one of the specified CAs, otherwise `false` ### tlsSocket.authorizationError The reason why the peer's certificate has not been verified. This property becomes available only when `tlsSocket.authorized === false`. ### tlsSocket.getPeerCertificate() Returns an object representing the peer's certificate. The returned object has some properties corresponding to the field of the certificate. 实例: ~~~ { subject: { C: 'UK', ST: 'Acknack Ltd', L: 'Rhys Jones', O: 'node.js', OU: 'Test TLS Certificate', CN: 'localhost' }, issuer: { C: 'UK', ST: 'Acknack Ltd', L: 'Rhys Jones', O: 'node.js', OU: 'Test TLS Certificate', CN: 'localhost' }, valid_from: 'Nov 11 09:52:22 2009 GMT', valid_to: 'Nov 6 09:52:22 2029 GMT', fingerprint: '2A:7A:C2:DD:E5:F9:CC:53:72:35:99:7A:02:5A:71:38:52:EC:8A:DF' } ~~~ 如果节点没有提供证书, 它将返回 `null` 或者一个空对象. ### tlsSocket.getCipher() 返回一个对象,表示了当前连接的cipher名与SSL/TLS协议版本。 Example: { name: 'AES256-SHA', version: 'TLSv1/SSLv3' } See SSL_CIPHER_get_name() and SSL_CIPHER_get_version() in [http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_CIPHERS](http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_CIPHERS) for more information. ### tlsSocket.renegotiate(options, callback) Initiate TLS renegotiation process. The `options` may contain the following fields: `rejectUnauthorized`, `requestCert` (See [tls.createServer](#) for details). `callback(err)` will be executed with `null` as `err`, once the renegotiation is successfully completed. NOTE: Can be used to request peer's certificate after the secure connection has been established. ANOTHER NOTE: When running as the server, socket will be destroyed with an error after `handshakeTimeout` timeout. ### tlsSocket.address() Returns the bound address, the address family name and port of the underlying socket as reported by the operating system. Returns an object with three properties, e.g. `{ port: 12346, family: 'IPv4', address: '127.0.0.1' }` ### tlsSocket.remoteAddress 远程IP地址的字符串表示。例如,`'74.125.127.100'`或 `'2001:4860:a005::68'`。 ### tlsSocket.remotePort 远程端口的数值表示。例如, `443`。 ### tlsSocket.localAddress 本地IP地址的字符串表达。 ### tlsSocket.localPort 本地端口的数值表示。