传输层安全(Transport Layer Security,TLS)和 安全套接字层(Secure Socket Layer,SSL)允许客户端/服务器应用程序以组织窃听和篡改的方式通过网络进行通信。他们会在传输层上对网络连接进行加密,这使得隐私和消息都能得到验证。
TLS是基于Netscape公司开发的早期SSL规范,实际上,TLS 1.0 也被成为 SSL 3.1。
公钥加密指需要两个独立的加密系统,一个秘钥用来加密明文,另一个用来解密已经加密的消息。其中一个秘钥是共有的,另一个是私有的。如果明文使用公钥进行加密,那么只能用私钥进行解密,这可以让公钥和私钥的拥有者进行私有通信。如果明文使用私钥加密的,公钥就可以对其进行解密,并且系统会验证私钥拥有者在文档上的签名。
公钥证书使用数字签名绑定公钥和身份信息、文档会由认证中心进行签名,完成验证匹配公钥的身份信息的过程。认证中心会响应其他证书,无论这个证书是自签名还是有其他认证中心签名的,这样就会形成一个授权链,这个授权链是公钥基础结构的一部分。
每台计算机都会定义一组根认证中心,在默认情况下用它们来验证认证和认链。在使用Node的TLS库时,可以使用这些默认的认证中心或者自定义的认证中心。
注意:
Node中的TLS是基于OpenSSL库实现的,可能你已经安装了,也可能没有,所以需要自己检查一下
TLS依赖于公钥/私钥基础结构,在这个基础结构中,每个客户端和服务器都必须有一个私钥对消息签名。
openssl程序可以在命令行上创建私钥:
$ openssl genrsa -out my_key.pem 1024
设计TLS的服务器和客户端在彼此验证的时候必须具有一个证书,是由认证中心签名或者自签名的公钥。获取证书的第一步是创建一个证书签发请求:
$ openssl req -new -key my_key.pem -out my_csr.pem
自签名:
$ openssl x509 -req -in my_csr.pem -signkey my_key.pem -out my_cert.pem
TLS服务器是net.Server
的子集,能用net.Server创建什么就能用TLS创建什么。但是使用TLS服务器的时候,使用的是安全连接。
初始化TLS服务器要复杂一些,因为还需要传入服务器的私钥和证书文件:
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./my_certificate.pem')
}
const server = tls.createServer(serverOptions);
server.listen(port);
当有连接到达,会发射secureConnection
事件,并将其传入套接字来注册回调函数。
server.on('secureConnection',(stream)=>{})
当有连接到达,回调函数可以拿到一个tls.CleartextStream
实例,该对象是一个双向流,只需要绑定data事件就可获取客户端数据。
server.on('secureConnection', (clientStream) => {
clientStream.on('data', (data)=>{
...
})
})
clientStream.write('hello');
clientStream.end("Bye!");
要创建到服务器的连接,首先需要发布秘钥和证书,没有则需要创建。
必须用几个选项来初始化客户端连接。首先需要获得这些选项,如果事先已经创建了私钥和数字证书,可以用fs读取他们:
const options = {
key: fs.readFileSync('...'),
cert: fs.readFileSync('...'),
}
使用tls.connect
连接服务器:
const client = tls.connect(port, host, options, () => {
...
})
是要和公钥允许你创建一个条安全信道,然而,在创建之后,你还想确认一下是否正确连接目标服务器,可以查看服务器证书。
为了能够查看服务器证书,需要学习一些未曾见过的TLS连接选项,其中之一就c,它是授权中心的缩写。如果忽略该选项,会使用默认的一组根证书。默认证书集会自用被客户端用来校验服务器信息。
如果成功,CleartextStream会将属性authorized设置为true。
client.write('Hello!');
一旦连接服务器,就可以监听data事件并接收数据:
client.on('data', (data)=>{
console.log(data);
})
client.end('bye');