不少人可能听过其中的超过3个名词,但它们究竟有什么关联呢?
TLS 是传输层安全协议(Transport Layer Security)的缩写,是一种对基于网络的传输的加密协议,可以在受信任的第三方公证基础上做双方的身份认证。TLS可以用在TCP上,也可以用在无连接的UDP报文上。协议规定了身份认证、算法协商、密钥交换等的实现。
SSL 是TLS的前身,现在已不再更新。
HTTPS 是在基于TLS/SSL的安全套接字上的的应用层协议,除了传输层进行了加密外,其它与常规HTTP协议基本保持一致
证书 是TLS协议中用来对身份进行验证的机制,是一种数字签名形式的文件,包含证书拥有者的公钥及第三方的证书信息。
证书分为2类:自签名证书和CA证书。一般自签名证书不能用来进行身份认证,如果一个server端使用自签名证书,client端要么被设置为无条件信任任何证书,要么需要将自签名证书的公钥和私钥加入受信任列表。但这样一来就增加了server的私钥泄露风险。
TLS基于CA的身份认证基本原理是:首先验证方需要信任CA提供方自己的证书(CAcert),比如证书在操作系统的受信任证书列表中,或者用户通过“安装根证书”等方式将CA的公钥和私钥加入受信任列表;然后CA对被验证方的原始证书进行签名(私钥加密),生成最终的证书;验证方得到最终的证书后,利用CAcert中包含的公钥进行解密,得到被验证方的原始证书。
根据RSA的加密原理,如果用CA的公钥解密成功,说明该证书的确是用CA的私钥加密的,可以认为被验证方是可信的。
微信小程序对第三方服务端的网络通信方式支持https和Websocket,WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,解决了HTTP协议效率低下的问题,能更好的节省服务器资源和带宽并达到实时通讯。
这里选择使用node.js配置本地服务器,它有很多websocket库,ws就是其中之一,号称最轻量级,最快。ws的用法比较简单,直接看https://github.com/websockets/ws就可以。
这里着重讲的是针对微信小程序实现的加入ssl证书的websocket实现。
生产环境建议你去买一个ssl证书,开发环境你可以给自己生成一个ssl自签名证书临时用一下。这里的开发环境为win7 X64系统。
下载链接:http://slproweb.com/products/Win32OpenSSL.html
这里建议下载32位版本(完全版),因为window任何版本都能使用。
!!!强烈建议下载v1.0.2的版本,千万不要用v1.1.0及更新的版本,因为会出现已经bug:“problem creating object tsa_policy1=1.2.3.4.1”!
如果安装过程出现这个窗口,说明你的电脑没有安装Visual C++ 2008 Redistributables, 请自行下载安装。
剩下的安装全部默认即可。我安装在 D:\OpenSSL-Win32 目录下。在这里我想将证书输出到 D盘根目录下,首先用管理员权限打开cmd(切记!!!)。
然后进入D盘根目录。在创建证书之前,你需要设置2个环境变量:
第二句告诉系统去哪找openssl.cfg文件。
现在可以运行OpenSSL了,cmd中输入 D:\OpenSSL-Win32\bin\openssl.exe运行。以上过程如图:
第一步:对于一个网站,首先必须有自己的私钥。为服务器创建一个1024位的RSA密钥,并保存到ca.key文件中:
openssl genrsa -out ssl.key 1024
如果想要添加密码保护,则改成以下命令:
openssl genrsa -des3 -out ssl.key 1024
利用私钥就可以生成证书了。OpenSSL使用x509命令生成证书。这里需要区分两个概念: 证书(certificate) 和 证书请求(certificate sign request)
证书是自签名或CA签名过的凭据,用来进行身份认证。
证书请求是对签名的请求,需要使用私钥进行签名
x509命令可以将证书和证书请求相互转换,不过我们这里只用到从证书请求到证书的过程。
第二步:从私钥或已加密的私钥均可以生成”证书请求”:
openssl req -new -key ssl.key -out ssl.csr
如果私钥已加密,需要输入密码。req命令会通过命令行要求用户输入国家、地区、组织等信息,这些信息会附加在证书中展示给连接方。
第三步:用私钥对“证书请求”进行签名生成证书crt。根据不同的场景,签名的方式也略有不同:
(一)自签名,生成私有证书
自签名的原理是用私钥对该私钥生成的“证书请求”进行签名,生成证书文件。该证书的签发者就是自己,所以验证方必须有该证书的私钥才能对签发信息进行验证,所以要么验证方信任一切证书,面临冒名顶替的风险,要么被验证方的私钥(或加密过的私钥)需要发送到验证方手中,面临私钥泄露的风险。
当然自签名也不是一无用处,比如需要内部通讯的两台电脑需要使用加密又不想用第三方证书,可以在两端使用相同的私钥和证书进行验证(当然这样就跟对称加密没有区别了)。自签名的方法为:
openssl x509 -req -in ssl.csr -signkey ssl.key -out ssl.crt
(二)自签名,生成CA证书
CA证书是一种特殊的自签名证书,可以用来对其它证书进行签名。这样当验证方选择信任了CA证书,被签名的其它证书就被信任了。在验证方进行验证时,CA证书来自操作系统的信任证书库,或者指定的证书列表。
openssl x509 -req -in sign.csr -extensions v3_ca -signkey sign.key -out sign.crt
(三)利用CA证书对其它证书进行签名
openssl x509 -req -in ssl.csr -extensions v3_usr -CA sign.crt -CAkey sign.key -CAcreateserial -out ssl.crt
如果想将下属CA密钥用于授权码签名(通过Microsoft’s signtool工具),你必须把密钥和证书打包进一个PKCS12文件。
pkcs12 -export -out ia.p12 -inkey ia.key -in ia.crt -chain -CAfile ca.crt
如果在上一节中,你将根CA和下属CA的Common Name设置成一样了,那么这一步你会得到这样的报错:
Error self signed certificate getting chain.
error in pkcs12
在Window上用signtool给可执行文件签名的方法:
在“受信仰的根证书颁发机构”存储区中安装 ia.p12 文件(如:双击它),然后用signtool /wizard为它签名。
在上面你创建的证书(.crt文件)也可以双击来查看和安装它:
首先找一个文件夹创建今天的代码文件:wss.js,并将上一篇生成的服务器私钥ssl.key和证书ssl.crt放在同目录下。
由于这里需要用到node.js的ws模块,所以通过npm命令进行下载。
这里需要注意,npm安装模块分为全局安装和局部安装,为了不污染全局环境,这里就把ws模块安装到server.js同目录下。
在 wss.js 目录下打开cmd,运行以下代码下载ws:
npm install ws
如果安装成功,会在目录下看到一个 node_modules 文件夹,里面有ws文件夹,表示ws模块已经安装成功。
// wss.js
const fs = require('fs');
// 一些配置信息
const cfg = {
port: 8888,
ssl_key: 'ssl.key',
ssl_cert: 'ssl.crt'
};
const httpServ = require('https');
const WebSocketServer = require('ws').Server; // 引用Server类
// 创建request请求监听器
const processRequest = (req, res) => {
res.writeHead(200);
res.end('厉害了,我的WebSockets!\n');
};
const app = httpServ.createServer({
// 向server传递key和cert参数
key: fs.readFileSync(cfg.ssl_key),
cert: fs.readFileSync(cfg.ssl_cert)
}, processRequest).listen(cfg.port);
// 实例化WebSocket服务器
const wss = new WebSocketServer({
server: app
});
// 如果有WebSocket请求接入,wss对象可以响应connection事件来处理
wss.on('connection', (wsConnect) => {
console.log('服务器已启动,监听中~');
wsConnect.on('message', (message) => {
console.log(`服务器接收到:${message}`);
wsConnect.send(`服务器回复: ${message}`, (err) => {
if (err) {
console.log(`服务器错误:${err}`);
}
});
});
});
提示:这里的 ${ }是ES6标准中的占位符,外层不是普通的 单引号,而是反引号,即左上角 ESC 键下面那个。
到此服务器代码已经写完,具体作用不解释了,注释应该能看懂。
在wss.js 目录下运行cmd,运行以下命令执行 wss.js :
node wss.js
此时服务器处于等待连接状态,此时在浏览器地址中打开网址:https://127.0.0.1/8888,如果看到浏览器中显示:厉害了,我的WebSockets!,则表示运行成功。
下面在支持javascript的浏览器的console中依次运行下面的客户端代码进行验证,查看服务器返回数据是否正确。
我使用的是QQ浏览器,在https://127.0.0.1/8888中按F12打开开发者窗口,并选择Console标签,依次输入以下代码:
const socket = new WebSocket('wss://127.0.0.1:8888/');
socket.onmessage = function (e) {
console.log('服务器: ' + e.data);
};
socket.send('你好,服务器');
!!!注意:以上代码要一个个运行,运行完上一条无误后,再运行下一条。
你会在Console中看到这些: