1 前言
前段时间比较系统地研究了SSL/TLS协议,并把它成功应用于一个系统原型中,实现了安全的互联网通信。
在系统原型中,Client端为各种常用Browser, 包括Chrome, Firefox, IE, Safari及android,ios的内置webview. Server端用NODEJS实现。
2 SSL/TLS协议简介
SSL 是Secure Socket Layer的缩写,TLS是Transport Layer Security的缩写, TLS是SSL的扩展,是用来取代SSL的。在普通的网络通信中加入TLS握手协议,可达到以下三个目的:
1) 消息加密与解密
消息加密后,第三方无法偷听
2) 消息完整性检查
消息加入hash码,防止被第三方篡改
3) 消息到达Intended目的地
握手时,会通过Certificate验明身份,防止第三方假冒目的地
在一个典型的TLS应用中,Client端的身份是不需要验证的,它一般通过密码机制实现。Server端身份则由第三方(Certificate Authority)提供的Certificate验证。TLS协议握手的步骤如下(简化版本):
1) ClientHello: Client向Server端发送Hello消息,启动握手。Hello消息包含自己有支持的SSL/TL版本,加解密算法及Key size.
2) ServerHello: Server端选择匹配的SSL/TLS版本,加解密算法,并把这些信息返回给Client端
3) Certificate: Server端发送自己的Certificate给Client。Certificate中包含Server的public key, domain name等。顺便提一句,public key与private key是一一对应的,经过public key加密的信息,从概率上来说,只有有private key的人才能解密。
4) Validate Server Identify: Client与CA通信,确认Certificate中的public key与 domain name是合法有效的。
5) Exchange secrete key: Secret key exchange: client端生成一个random的secret key, 并用public key加密。
6) Exchange secrete key: Server端用private key解密被加密的secret key,这样Client与Server会share同一个secret key.
7) 利用同一个secret key, Client 与Server就可以加密解密接下来的所有消息通讯了(这是用的加解密算法为对称性加解密算法,诸如AES, Blowfish, Camellia, SEED等)。
3 获取SSL/TLS证书
SSL/TLS 的一个关键环节就是SSL/TLS证书。已经有了很多免费与开源的SSL/TLS库,如PolarSSL, CyaSSL, OpenSSL, NSS, or GnuTLS。JSSE也有实现,开发者可以根据需要自由选择。选择的库不同,获取SSL/TLS证书的步骤与方法也会稍有不同,但是大的流程与原理是相同的,毕竟只是同一协议的不同实现而已。
Node.js中用了Open SSL,所以接下来的介绍就以Open SSL 为准。
3.1 下载/安装Open SSL
如果你使用的是windows,又不想自己编译生成Open SSL. 你可以下个Open SSL 的windows版本安装包。地址如下:
http://slproweb.com/products/Win32OpenSSL.html
3.2 生成Private key
在Command line tool 里,输入如下:
set OPENSSL_CONF=C:\OpenSSL-Win32\bin\openssl.cfg
openssl genrsa -out 2-key.pem 1024
第一行的目的是为了设置Open SSL的运行环境,否则会报warning的。
3.3 生成CSR
openssl req -new -key 2-key.pem -out 2-csr.pem
3.4 生成证书
3.4.1 Self-signed 证书
openssl x509 -req -in 2-csr.pem -signkey 2-key.pem -out 2-cert.pem
你可以生成self-signed 证书,这样就不需要付钱。但它的缺点有二点:
1) 第一次使用时,因为不被Browser识别,所以会弹出对话框,要求用户允许。
2) 在Ios的uiwebview中不能使用,会fail silently.
3.4.2 CA证书
你也可以花钱从certificate authority 那里买,我就从namecheap那买了一个,60元。有效期一年。
4 安装SSL/TLS证书
Server环境不同,安装证书的步骤也会不同。本文以NODE.JS为准。
4.1 Server端
刷了卡后,很快就从namecheap那收到了邮件,里面有三个文件:
- Root CA Certificate - AddTrustExternalCARoot.crt
- Intermediate CA Certificate - PositiveSSLCA2.crt
- Your PositiveSSL Certificate - www_domainname_com.crt
利用一个文件编辑器,拼接PositiveSSLCA2.crt与AddTrustExternalCARoot.crt,生成一个新的文件domainname.ca-bundle。该文件是CA的Certificate.
然后就可以在node.js里设置证书了:
var tlsOptions={
ca: fs.readFileSync(__dirname + '/pesoftexploration.ca-bundle'),
key: fs.readFileSync(__dirname + '/key.key'),
cert: fs.readFileSync(__dirname + '/cert.crt')
};
var port = 8080;
//set up https
var express = require('express');
var app = express.createServer(tlsOptions);
4.2 Client端
Client端的实现比较简单,只要把以前的http改成https就行了。
socket = io.connect(https://www.domainname.com:8080/);
5 总结
本文介绍了SSL/TLS协议的握手步骤与及如何在NODE.JS中布署SSL/TLS. 重点是把我个人对SSL/TLS探索过程中遇到的关键点与难点作了阐述,很多地方讲得并不是很详细,如果感兴趣,可以阅读参考中列出的文章。
6 参考
http://en.wikipedia.org/wiki/Transport_Layer_Security
http://en.wikipedia.org/wiki/OpenSSL
http://java.sun.com/developer/technicalArticles/Security/secureinternet/
http://www.mobilefish.com/developer/openssl/openssl_quickguide_code_examples.html
http://jaspreetchahal.org/warning-cant-open-config-file-usrlocalsslopenssl-cnf/
http://slproweb.com/products/Win32OpenSSL.html
http://stackoverflow.com/questions/6658557/alternative-to-ssl-manual-encryption
http://blog.derekperez.com/post/4489069081/debugging-errors-within-nodejs
http://stackoverflow.com/questions/933331/how-to-use-nsurlconnection-to-connect-with-ssl-for-an-untrusted-cert/2033823#2033823
http://serverfault.com/questions/329585/ec2-is-an-instances-public-dns-stable-can-i-rely-on-it-not-changing
http://stackoverflow.com/questions/5679509/free-trustable-ssl-certificates
http://qugstart.com/blog/node-js/install-comodo-positivessl-certificate-with-node-js/