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/