通过require('tls')
来使用这个模块。
tls
模块使用OpenSSL来提供传输层的安全 和/或 安全socket
层:已加密的流通信。
TLS/SSL是一种公/私钥架构。每个客户端和每个服务器都必须有一个私钥。一个私钥通过像如下的方式创建:
openssl genrsa -out ryans-key.pem 2048
所有的服务器和部分的客户端需要一个证书。证书是被CA签名或自签名的公钥。获取一个证书第一步是创建一个“证书签署请求(Certificate Signing Request)”(CSR)文件。通过:
openssl req -new -sha256 -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交给一个CA请求签名。
为了完全向前保密(PFS),需要产生一个 迪菲-赫尔曼 参数:
openssl dhparam -outform PEM -out dhparam.pem 2048
创建.pfx
或.p12
,通过:
openssl pkcs12 -export -in agent5-cert.pem -inkey agent5-key.pem \
-certfile ca-cert.pem -out agent5.pfx
CA certs
串联在一个文件中,就像cat ca1-cert.pem ca2-cert.pem > ca-cert.pem
。TLS协议让客户端可以重新协商某些部分的TLS会话。不幸的是,会话重协商需要不相称的服务器端资源,这它可能成为潜在的DOS攻击。
为了减缓这种情况,重新协商被限制在了每10分钟最多3次。当超过阀值时,tls.TLSSocket
会触发一个错误。阀值是可以调整的:
tls.CLIENT_RENEG_LIMIT: 重新协商限制,默认为3
。
tls.CLIENT_RENEG_WINDOW: 重新协商窗口(秒),默认为10分钟。
除非你知道你在做什么,否则不要改变默认值。
为了测试你的服务器,使用openssl s_client -connect address:port
来连接它,然后键入R<CR>
(字母R
加回车)多次。
NPN
(下个协议协商)和SNI(服务器名称指示)都是TLS握手拓展,它们允许你:
术语“向前保密”或“完全向前保密”描述了一个密钥-协商(如密钥-交换)方法的特性。事实上,它意味着,甚至是当(你的)服务器的私钥被窃取了,窃取者也只能在他成功获得所有会话产生的密钥对时,才能解码信息。
它通过在每次握手中(而不是所有的会话都是同样的密钥)随机地产生用于密钥-协商的密钥对来实现。实现了这个技术的方法被称作“ephemeral”。
目前有两种普遍的方法来实现完全向前保密:
ephemeral
版本。ephemeral
版本。ephemeral
方法可能有一些性能问题,因为密钥的生成是昂贵的。
返回支持的SSL加密器的名字数组。
例子:
var ciphers = tls.getCiphers();
console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...]
创一个新的tls.Server
实例。connectionListener
参数被自动添加为secureConnection
事件的监听器。options
参数可以有以下属性:
pfx: 一个包含PFX
或PKCS12
格式的私钥,加密凭证和CA证书的字符串或buffer
。
key: 一个带着PEM
加密私钥的字符串(可以是密钥数组)(必选)。
passphrase: 一个私钥或pfx
密码字符串。
cert: 一个包含了PEM
格式的服务器证书密钥的字符串或buffer
(可以是cert
数组)(必选)。
ca: 一个PEM
格式的受信任证书的字符串或buffer
数组。如果它被忽略,将使用一些众所周知的“根”CA,像VeriSign
。这些被用来授权连接。
crl : 一个PEM
编码的证书撤销列表(Certificate Revocation List)字符串或字符串行表。
ciphers: 一个描述要使用或排除的加密器的字符串,通过:
分割。默认的加密器套件是:
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
默认的加密器套件更倾向于Chrome's 'modern cryptography' setting
的GCM加密器,也倾向于PFC的ECDHE和DHE加密器,它们提供了一些向后兼容性。
鉴于specific attacks affecting larger AES key sizes
,所以更倾向于使用128位的AES而不是192和256位的AES。
旧的依赖于不安全的和弃用的RC4或基于DES的加密器(像IE6)的客户端将不能完成默认配置下的握手。如果你必须支持这些客户端,TLS推荐规范
可能提供了一个兼容的加密器套件。更多格式细节,参阅OpenSSL cipher list format documentation
。
ECDH
密钥协商的已命名的椭圆的字符串,如果要禁用ECDH
,就设置为false
。默认值为prime256v1
(NIST P-256)。使用crypto.getCurves()
来获取一个可用的椭圆列表。在最近的发行版中,运行openssl ecparam -list_curves
命令也会展示所有可用的椭圆的名字和描述。
dhparam: 一个包含了迪菲-赫尔曼参数的字符串或buffer
,要求有完全向前保密。使用openssl dhparam
来创建它。它的密钥长度需要大于等于1024字节,否则会抛出一个错误。强力推荐使用2048或更多位,来获取更高的安全性。如果参数被忽略或不合法,它会被默默丢弃并且DHE
加密器将不可用。
handshakeTimeout: 当SSL/TLS握手在这个指定的毫秒数后没有完成时,终止这个链接。默认为120秒。
当握手超时时,tls.Server
会触发一个clientError
事件。
honorCipherOrder : 选择一个加密器时,使用使用服务器的首选项而不是客户端的首选项。默认为true
。
requestCert: 如果设置为true
,服务器将会向连接的客户端请求一个证书,并且试图验证这个证书。默认为true
。
rejectUnauthorized: 如果设置为true
,服务器会拒绝所有没有在提供的CA列表中被授权的客户端。只有在requestCert
为true
时这个选项才有效。默认为false
。
NPNProtocols: 一个可用的NPN
协议的字符串或数组(协议应该由它们的优先级被排序)。
SNICallback(servername, cb): 当客户端支持SNI TLS
扩展时,这个函数会被调用。这个函数会被传递两个参数:servername和cb。SNICallback
必须执行cb(null, ctx)
,ctx
是一个SecureContext
实例(你可以使用tls.createSecureContext(...)
来获取合适的SecureContext
)。如果SNICallback
没有被提供 - 默认的有高层次API的回调函数会被使用(参阅下文)。
sessionTimeout: 一个指定在TLS会话标识符和TLS会话门票(tickets)被服务器创建后的超时时间。更多详情参阅SSL_CTX_set_timeout
。
ticketKeys: 一个由16字节前缀,16字节hmac密钥,16字节AEC密钥组成的48字节buffer
。你可以使用它在不同的tls
服务器实例上接受tls
会话门票。
注意:会在cluster
模块工作进程间自动共享。
sessionIdContext: 一个包含了会话恢复标识符的字符串。如果requestCert
为true
,默认值是通过命令行生成的MD5哈希值。否则,就将不提供默认值。
secureProtocol: 将要使用的SSL方法,举例,SSLv3_method
将强制使用SSL v3。可用的值取决于OpenSSL的安装和SSL_METHODS
常量中被定义的值。
下面是一个简单应答服务器的例子:
var tls = require('tls');
var fs = require('fs');
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
// This is necessary only if the client uses the self-signed certificate.
ca: [ fs.readFileSync('client-cert.pem') ]
};
var server = tls.createServer(options, function(socket) {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.write("welcome!\n");
socket.setEncoding('utf8');
socket.pipe(socket);
});
server.listen(8000, function() {
console.log('server bound');
});
或
var tls = require('tls');
var fs = require('fs');
var options = {
pfx: fs.readFileSync('server.pfx'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
};
var server = tls.createServer(options, function(socket) {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.write("welcome!\n");
socket.setEncoding('utf8');
socket.pipe(socket);
});
server.listen(8000, function() {
console.log('server bound');
});
你可以通过openssl s_client
来连接服务器:
openssl s_client -connect 127.0.0.1:8000
根据给定的 端口和主机(旧API)或 options.port
和options.host
创建一个新的客户端连接。如果忽略了主机,默认为localhost
。options
可是一个含有以下属性的对象:
host: 客户端应该连接到的主机。
port: 客户端应该连接到的端口。
socket: 根据给定的socket
的来建立安全连接,而不是创建一个新的socket
。如果这个选项被指定,host
和port
会被忽略。
path: 创建到path
的unix socket
连接。如果这个选项被指定,host
和port
会被忽略。
pfx: 一个PFX
或PKCS12
格式的包含了私钥,证书和CA证书的字符串或buffer
。
key: 一个PEM
格式的包含了客户端私钥的字符串或buffer
(可以是密钥的数组)。
passphrase: 私钥或pfx
的密码字符串。
cert: 一个PEM
格式的包含了证书密钥的字符串或buffer
(可以是密钥的数组)。
ca: 一个PEM
格式的受信任证书的字符串或buffer
数组。如果它被忽略,将使用一些众所周知的CA,像VeriSign
。这些被用来授权连接。
ciphers: 一个描述了要使用或排除的加密器,由:
分割。使用的默认加密器套件与tls.createServer
使用的一样。
rejectUnauthorized: 若被设置为true
,会根据提供的CA列表来验证服务器证书。当验证失败时,会触发error
事件;err.code
包含了一个OpenSSL错误码。默认为true
。
NPNProtocols: 包含支持的NPN协议的字符串或buffer
数组。buffer
必须有以下格式:0x05hello0x05world
,第一个字节是下一个协议名的长度(传递数组会更简单:['hello', 'world']
)。
servername: SNI
TLS 扩展的服务器名。
checkServerIdentity(servername, cert): 为根据证书的服务器主机名检查提供了覆盖。必须在验证失败时返回一个错误,验证通过时返回undefined
。
secureProtocol: 将要使用的SSL方法,举例,SSLv3_method
将强制使用SSL v3。可用的值取决于OpenSSL的安装和SSL_METHODS
常量中被定义的值。
session: 一个Buffer
实例,包含了TLS会话。
callback
参数会被自动添加为secureConnect
事件的监听器。
tls.connect()
返回一个tls.TLSSocket
对象。
以下是一个上述应答服务器的客户端的例子:
var tls = require('tls');
var fs = require('fs');
var options = {
// These are necessary only if using the client certificate authentication
key: fs.readFileSync('client-key.pem'),
cert: fs.readFileSync('client-cert.pem'),
// This is necessary only if the server uses the self-signed certificate
ca: [ fs.readFileSync('server-cert.pem') ]
};
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 tls = require('tls');
var fs = require('fs');
var options = {
pfx: fs.readFileSync('client.pfx')
};
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();
});
net.Socket
实例的包装,替换了内部socket
的 读/写例程,来提供透明的对 传入/传出数据 的 加密/解密。
根据已存在的TCPsocket
,构造一个新的TLSSocket
对象。
socket
是一个net.Socket
实例。
options
是一个可能包含以下属性的对象:
secureContext: 一个可选的通过tls.createSecureContext( ... )
得到的TLS内容对象。
isServer: 如果为true
,TLS socket
将会在服务器模式(server-mode)下被初始化。
server: 一个可选的net.Server
实例。
requestCert: 可选,参阅tls.createSecurePair
。
rejectUnauthorized: 可选,参阅tls.createSecurePair
。
NPNProtocols: 可选,参阅tls.createServer
。
SNICallback: 可选,参阅tls.createServer
。
session: 可选,一个Buffer
实例,包含了TLS会话。
requestOCSP: 可选,如果为true
,OCSP
状态请求扩展将会被添加到客户端 hello,并且OCSPResponse
事件将会在建立安全通信前,于socket
上触发。
创建一个证书对象,details
有可选的以下值:
PFX
或PKCS12
编码的私钥,证书和CA证书的字符串或buffer
。PEM
编码的私钥的字符串。pfx
密码字符串。PEM
加密证书的字符串。PEM
加密CA证书的字符串或字符串行表。PEM
加密CRL
的字符串或字符串行表。http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT
。true
。更多细节参阅tls
模块文档。如果没有指定ca
,那么io.js
将会使用http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt
提供的默认公共可信任CA列表。
根据两个流,创建一个新的安全对(secure pair)对象,一个是用来读/写加密数据,另一个是用来读/写明文数据。通常加密的数据是从加密数据流被导流而来,明文数据被用来作为初始加密流的一个替代。
credentials: 一个通过tls.createSecureContext( ... )
得到的安全内容对象。
isServer: 一个表明了 是否这个tls
连接应被作为一个服务器或一个客户端打开 的布尔值。
requestCert: 一个表明了 是否服务器应该向连接的客户端请求证书 的布尔值。只应用于服务器连接。
rejectUnauthorized: 一个表明了 是否服务器应该拒绝包含不可用证书的客户端 的布尔值。只应用于启用了requestCert
的服务器。
tls.createSecurePair()
返回一个带有cleartext
和 encrypted
流 属性的对象。
注意:cleartext
和tls.TLSSocket
有相同的API。
由tls.createSecurePair
返回。
当SecurePair
成功建立一个安全连接时,SecurePair
会触发这个事件
与检查服务器的secureConnection
事件相似,pair.cleartext.authorized
必须被检查,来确认证书是否使用了合适的授权。
这是一个net.Server
的子类,并且与其有相同的方法。除了只接受源TCP连接,这个类还接受通过TLS或SSL加密的数据。
当一个新连接被成功握手后,这个事件会被触发。参数是一个tls.TLSSocket
实例。它拥有所有普通流拥有的事件和方法。
socket.authorized
是一个表明了 客户端是否通过提供的服务器CA来进行了认证 的布尔值。如果socket.authorized
为false
,那么socket.authorizationError
将被设置用来描述授权失败的原因。一个不明显的但是值得提出的点:依靠TLS服务器的设定,未授权的连接可能会被接受。socket.npnProtocol
是一个包含了被选择的NPN协议的字符串。socket.servernam
是一个包含了通过SNI请求的服务器名的字符串。
当安全连接被建立之前,服务器触发了一个error
事件 - 它会被转发到这里。
tlsSocket
是错误来自的tls.TLSSocket
。
在TLS会话创建时触发。可能会被用来在外部存储会话。callback
必须最终被执行,否则安全连接将不会收到数据。
注意:这个事件监听器只会影响到它被添加之后建立的连接。
当客户端想要恢复先前的TLS会话时触发。事件监听器可能会在外部通过sessionId
来寻找会话,并且在结束后调用callback(null, sessionData)
。如果会话不能被恢复(例如没有找到),可能会调用callback(null, null)
。调用callback(err)
会关闭将要到来的连接并且销毁socket
。
注意:这个事件监听器只会影响到它被添加之后建立的连接。
当客户端发送一个证书状态请求时触发。你可以解释服务器当前的证书来获取OCSP url和证书id,并且在获取了OCSP响应后执行callback(null, resp)
,resp
是一个Buffer
实例。certificate
和issuer
都是一个Buffer
,即主键和发起人证书的DER代表(DER-representations)。它们可以被用来获取OCSP证书id 和 OCSP末端url。
另外,callback(null, null)
可以被调用,意味着没有OCSP响应。
调用callback(err)
,将会导致调用socket.destroy(err)
。
典型的流程:
OCSPRequest
给它(通过ClientHello
中扩展的状态信息)。OCSPRequest
事件监听器(如果存在)。OCSPResponse
,然后通过回调函数的参数将其返回给客户端。socket
或者进行握手。注意:issuer
可以是null
,如果证书是自签名的或issuer
不在根证书列表之内(你可以通过ca
参数提供一个issuer
)。
注意:这个事件监听器只会影响到它被添加之后建立的连接。
注意:你可能想要使用一些如asn1.js
的npm
模块来解释证书。
从指定的端口和主机名接收连接。如果hostname
被忽略,服务器会在当IPv6可用时,接受任意IPv6地址(::
)上的连接,否则为任意IPv4(0.0.0.0
)上的。将port
设置为0
则会赋予其一个随机端口。
这个函数是异步的。最后一个参数callback
会在服务器被绑定后执行。
更多信息请参阅net.Server
。
阻止服务器继续接收新连接。这个函数是异步的,当服务器触发一个close
事件时,服务器将最终被关闭。可选的,你可以传递一个回调函数来监听close
事件。
返回绑定的地址,服务器地址的协议族名和端口通过操作系统报告。更多信息请参阅net.Server.address()
。
添加安全内容,它将会在如果客户端请求的SNI主机名被传递的主机名匹配(可以使用通配符)时使用。context
可以包含密钥,证书,CA 和/或 其他任何tls.createSecureContext
的options
参数的属性。
当服务器连接数变多时,设置这个值来拒绝连接。
服务器上的当前连接数。
稳定度: 0 - 弃用。 使用
tls.TLSSocket
替代。
这是一个加密流。
一个底层socket
的bytesWritten
存取器的代理,它会返回写入socket
的总字节数,包括TLS开销。
这是一个net.Socket
的包装,但是对写入的数据做了透明的加密,并且要求TLS协商。
这个实例实现了一个双工流接口。它有所有普通流所拥有的事件和方法。
在一个新连接成功握手后,这个事件被触发。无论服务器的证书被授权与否,这个监听器都会被调用。测试tlsSocket.authorized
来 验证服务器证书是否被一个指定CA所签名 取决于用户。如果tlsSocket.authorized === false
那么错误可以从tlsSocket.authorizationError
里被发现。如果NPN
被使用,你可以通过tlsSocket.npnProtocol
来检查已协商协议。
如果requestOCSP
选项被设置,这个事件会触发。response
是一个buffer
对象,包含了服务器的OCSP响应。
习惯上,response
是一个来自服务器的CA(包含服务器的证书撤销状态)的已签名对象。
静态布尔变量,总是true
。可能会被用来区分TLS socket
和普通的socket
。
如果对等(peer)证书通过一个指定的CA被签名,那么这个值为true
。否则为false
。
对等(peer)的证书没有被验证的原因。这个值只在tlsSocket.authorized === false
时可用。
返回了一个代表了对等证书的对象。返回的对象有一些属性与证书的属性一致。如果detailed
参数被设置为true
,issuer
属性的完整链都会被返回,如果为false
,只返回不包含issuer
属性的顶端的证书。
例子:
{ subject:
{ C: 'UK',
ST: 'Acknack Ltd',
L: 'Rhys Jones',
O: 'io.js',
OU: 'Test TLS Certificate',
CN: 'localhost' },
issuerInfo:
{ C: 'UK',
ST: 'Acknack Ltd',
L: 'Rhys Jones',
O: 'io.js',
OU: 'Test TLS Certificate',
CN: 'localhost' },
issuer:
{ ... another certificate ... },
raw: < RAW DER buffer >,
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',
serialNumber: 'B9B0D332A1AA5635' }
如果peer
没有提供一个证书,那么会返回null
或空对象。
返回一个代表了当前连接的加密器名和SSL/TLS协议版本的对象。
例子: { name: 'AES256-SHA', version: 'TLSv1/SSLv3' }
参阅http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_CIPHERS
中SSL_CIPHER_get_name()
和SSL_CIPHER_get_version()
。
初始化TLS重新协商过程。optios
可以包含以下属性:rejectUnauthorized
,requestCert
(详情参阅tls.createServer
)。一旦重协商成功,callback(err)
会带着err
为null
执行。
注意:可以被用来请求对等(peer)证书在安全连接建立之后。
另一个注意点:当作为服务器运行时,socekt
在handshakeTimeout
超时后,会带着一个错误被销毁。
设置TLS碎片大小的最大值(默认最大值为16384
,最小值为512
)。若设置成功返回true
,否则返回false
。
更小的碎片大小来减少客户端的缓冲延迟:大的碎片通过TLS层缓冲,直到收到全部的碎片并且它的完整性被验证;大碎片可能会跨越多次通信,并且可能会被报文丢失和重新排序所延迟。但是,更小的碎片增加了额外的TLS框架字节和CPU开销,可能会减少总体的服务器负载。
返回ASN.1
编码的TLS会话,如果没有被协商,返回undefined
。可以被用在重新连接服务器时,加速握手的建立。
注意:仅在客户端TLS socket
中工作。仅在调试时有用,因为会话重新使用了给tls.connect
提供的session
选项。
返回TLS会话门票(ticket),如果没有被协商,返回undefined
。
返回绑定的地址,协议族名和端口由底层系统报告。返回一个含有三个属性的对象,例如:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }
。
代表了远程IP地址的字符串。例子:'74.125.127.100'
或'2001:4860:a005::68'
。
代表了远程IP协议族的字符串。'IPv4'
或'IPv6'
。
代表了远程端口数字。例子:443
。
代表了本地IP地址的字符串。
代表了本地端口的数字。