Node.js tls模块使用OpenSSL实现TLS/SSL安全通讯--构建TLS客户端

 2015年09月05日    1536     声明


要连接到一个TLS服务器,也要需要密钥和证书。在Node.js的tls模块中,可以通过tls.connet()方法创建一个tls.TLSSocket,该实例是tls.Socket 的安全版本。创建OpenSSL密钥和证书请可参考:使用OpenSSL创建TLS/SSL公钥、私钥

  1. 初始化客户端
  2. 服务器验证状态
  3. 与服务器证交互数据
  4. 断开连接
  5. 运行TLS客户端


1. 初始化客户端

初始化tls客户关,可以使用tls.connect()方法,或是使用构造函数new tls.TLSSocket(socket, options)从现有net.Socket的实例创建。这两种方法都会返回一个tls.TLSSocket对象实例。

var tls = require('tls');
var fs = require('fs');

//使用客户端私钥和证书创建服务器
var options = {
    key: fs.readFileSync('./ssl/client-key.pem'),
    cert: fs.readFileSync('./ssl/client-cert.pem'),
	
    // 服务端使用的自签名证书认证
    ca: [ fs.readFileSync('./ssl/itbilu-cert.pem') ]
};

//使用pfx或p12证书文件创建
/*
var options = {
    pfx: fs.readFileSync('./ssl/client.pfx')
};
*/

var tlsSocket = tls.connect(3333, options, function () {
    console.log('连接成功');
})

上面使用两种方式创建了tls.TLSSocket对象实例。与创建net.Socket实例不同,需要传入客户端的私钥和证书等文件。tls.connect()方法使用详解如下:

tls.connect(port[, host][, options][, callback]):从指定的端口port和主机host创建一个到TLS服务器的客户端连接,这是一老版本 API,建议使用下面的方法代替。

tls.connect(options[, callback]):从指定的选项options创建一个到TLS服务器的客户端连接。options是一个包含以下值的对象:

  • host:客户端需要连接到的主机

  • port:客户端需要连接到的主机端口

  • socket:在指定的socket对象(非新建)上建立安全连接。

    如果存在这个参数值,将忽略hostport参数。/p>

  • path:在指定的unix socket路径上创建连接。

    如果存在这个参数值,将忽略hostport参数。/p>

  • pfx:包含私钥、证书和服务器的CA证书(PFX 或 PKCS12 格式)字符串或缓存Buffer。(key, certca互斥)。

  • key:包含客户端(PEM格式)的私钥字符串或Buffer缓存。可以是 keys 数组。

  • passphrase:私钥或pfx的密码字符串。

  • cert:包含客户端证书(PEM 格式)字符串或缓存Buffer。可以是certs的数组。

  • ca: 信任的ca证书(PEM 格式)的字符串或缓存Buffer数组。如果忽略这个参数,将会使用或缓存"root" CAs,用来授权连接,如:VeriSign。

  • rejectUnauthorized:如果为true,服务器证书根据CAs授权列表验证。如果验证失败,触发'error'事件;事件回调函数中的errerr.code为OpenSSL错误代码。本参数默认值为true

  • NPNProtocols:一个包含NPN协议的Buffer数组。

  • servername:SNI(Server Name Indication,域名标识)TLS扩展的服务器名。

  • secureProtocol:SSL使用的方法。如:SSLv3_method强制 SSL 版本为3。可传入的值取决于你所安装的 OpenSSL 中的常量,参考:SSL_METHODS

  • session:一个包含 TLS 会话Buffer实例。


2. 服务器验证状态

使用公钥和私钥可以在客户端和服务器之间建立一条安全的通道,为了验证客户端在服务器的授权状态,可以通过tls.TLSSocket对象中authorized属性是否已得到服务器授权。但根据 TLS 服务器的设置,未授权连接可能也会被服务器接受接受。

var tlsSocket = tls.connect(3333, options, function () {
    console.log('连接成功');
    console.log('客户端认证状态:%s', tlsSocket.authorized);
})


3. 与服务器证交互数据

tls.TLSSocket对象是一个可读写的Stream流,因此,可以通过write()方法向服务端发送数据。通过监听'data',可以接收服务器数据。

var tlsSocket = tls.connect(3333, options, function () {
    console.log('连接成功');
    console.log('客户端认证状态:%s', tlsSocket.authorized);
    //向服务器发送数据
    tlsSocket.write('Hello itbilu.com');
});

//接收服务器数据
tlsSocket.on('data', function(data){
    console.log('收到服务器数据:%s', data);
});


4. 断开连接

在客户端,可以通过调用tls.TLSSockt对象的end方法,断开与服务器的连接,该方法也可以接收一个参数,参数为字符串或缓冲区Buffer,这些数据发送完毕后将断开与服务器的连接。

var tlsSocket = tls.connect(3333, options, function () {
    console.log('连接成功');
    console.log('客户端认证状态:%s', tlsSocket.authorized);
    //断开与服务器的连接
    tlsSocket.end('bye ~ itbilu.com');
});


5. 运行TLS客户端

完整代码整理如下:

var tls = require('tls');
var fs = require('fs');

//使用客户端私钥和证书创建服务器
var options = {
    key: fs.readFileSync('./ssl/client-key.pem'),
    cert: fs.readFileSync('./ssl/client-cert.pem'),

    // 服务端使用的自签名证书认证
    ca: [ fs.readFileSync('./ssl/itbilu-cert.pem') ]
};

//使用pfx或p12证书文件创建
/*
var options = {
    pfx: fs.readFileSync('./ssl/client.pfx')
};
*/

var tlsSocket = tls.connect(3333, options, function () {
    console.log('连接成功');
    console.log('客户端认证状态:%s', tlsSocket.authorized);
    //向服务器发送数据
    tlsSocket.write('Hello itbilu.com');
    //断开与服务器的连接
    tlsSocket.end('bye ~ itbilu.com');
});

//接收服务器数据
tlsSocket.on('data', function(data){
    console.log('收到服务器数据:%s', data);
});

保存以上代码。运行上篇文章示例,并node运行本示例,即可查看这个简单的TLS服务器TLS客户端通讯运行效果。

服务端运行效果:

客户端运行效果: