netty系列之:對聊天進行加密

flydean 2021-08-15 16:36:12 阅读数:287

本文一共[544]字,预计阅读时长:1分钟~
netty 系列 聊天 加密

簡介

在之前的文章中,我們講到了怎麼使用netty建立聊天室,但是這樣的簡單的聊天室太容易被竊聽了,如果想要在裏面說點悄悄話是很不安全的,怎麼辦呢?學過密碼學的朋友可能就想到了一個解决辦法,聊天的時候對消息加密,處理的時候再對消息解密即可。

當然在netty中上述的工作都不需要我們手動來實現,netty已經提供了支持SSL的channel供我們選擇,一起來看看吧。

PKI標准

在講netty的具體支持之前,我們需要先了解一下公鑰和私鑰的加密標准體系PKI。PKI的全稱是Public Key Infrastructure,也就是公鑰體系。用於規範公鑰私募進行加密解密的規則,從而便於不同系統的對接。

事實上PKI標准已經有兩代協議了。

第一代的PKI標准主要是由美國RSA公司的公鑰加密標准PKCS,國際電信聯盟的ITU-T X.509,IETF的X.509,WAP和WPKI等標准組成。但是因為第一代PKI標准是基於抽象語法符號ASN.1進行編碼的,實現起來比較複雜和困難,所以產生了第二代PKI標准。

第二代PKI標准是由微軟、VeriSign和webMethods三家公司在2001年發布的基於XML的密鑰管理規範也叫做XKMS。

事實上現在CA中心使用的最普遍的規範還是X.509系列和PKCS系列。

X.509系列主要由X.209、X.500和X.509組成,其中X.509是由國際電信聯盟(ITU-T)制定的數字證書標准。在X.500基礎上進行了功能增强,
X.509是在1988年發布的。X.509證書由用戶公共密鑰和用戶標識符組成。此外還包括版本號、證書序列號、CA標識符、簽名算法標識、簽發者名稱、證書有效期等信息。

而PKCS是美國RSA公司的公鑰加密標准,包括了證書申請、證書更新、證書作廢錶發布、擴展證書內容以及數字簽名、數字信封的格式等方面的一系列相關協議。它定義了一系列從PKCS#1到PKCS#15的標准。

其中最常用的是PKCS#7、PKCS#12和PKCS#10。PKCS#7 是消息請求語法,常用於數字簽名與加密,PKCS#12是個人消息交換與打包語法主要用來生成公鑰和私鑰。PKCS#10是證書請求語法。

各類證書的後綴和轉換

操作過證書的朋友可能會對證書的後綴眼花繚亂,一般來說會有DER、CRT、CER、PEM這幾種證書的後綴。

DER錶示證書的內容是用二進制進行編碼的。

PEM文件是一個文本文件,其內容是以“ - BEGIN -” 開頭的,Base64編碼的字符。

CRT和CER基本上是等價的,他們都是證書的擴展,也是文本文件,不同的是CRT通常用在liunx和unix系統中,而CER通常用在windows系統中。並且在windows系統中,CER文件會被MS cryptoAPI命令識別,可以直接顯示導入和/或查看證書內容的對話框。

KEY文件,主要用來保存PKCS#8標准的公鑰和私鑰。

下面的命令可以用來查看文本證書內容:

openssl x509 -in cert.pem -text -noout
openssl x509 -in cert.cer -text -noout
openssl x509 -in cert.crt -text -noout

下面的命令可以用來查看二進制證書內容:

openssl x509 -in cert.der -inform der -text -noout

下面是常見的PEM和DER相互轉換:

PEM到DER
openssl x509 -in cert.crt -outform der-out cert.der
DER到PEM
openssl x509 -in cert.crt -inform der -outform pem -out cert.pem

netty中啟動SSL server

事實上這個標題是不對的,netty中啟動的server還是原來那個server,只是對發送的消息進行了加密解密處理。也就是說添加了一個專門進行SSL操作的Handler。

netty中代錶ssl處理器的類叫做SslHandler,它是SslContext工程類的一個內部類,所以我們只需要創建好SslContext即可通過調用newHandler方法來返回SslHandler。

讓服務器端支持SSL的代碼:

 ChannelPipeline p = channel.pipeline();
SslContext sslCtx = SslContextBuilder.forServer(...).build();
p.addLast("ssl", sslCtx.newHandler(channel.alloc()));

讓客戶端支持SSL的代碼:

ChannelPipeline p = channel.pipeline();
SslContext sslCtx = SslContextBuilder.forClient().build();
p.addLast("ssl", sslCtx.newHandler(channel.alloc(), host, port));

netty中SSL的實現有兩種方式,默認情况下使用的是OpenSSL,如果OpenSSL不可以,那麼將會使用JDK的實現。

要創建SslContext,可以調用SslContextBuilder.forServer或者SslContextBuilder.forClient方法。

這裏以server為例,看下創建流程。SslContextBuilder有多種forServer的方法,這裏取最簡單的一個進行分析:

 public static SslContextBuilder forServer(File keyCertChainFile, File keyFile) {
return new SslContextBuilder(true).keyManager(keyCertChainFile, keyFile);
}

該方法接收兩個參數,keyCertChainFile是一個PEM格式的X.509證書文件,keyFile是一個PKCS#8的私鑰文件。

熟悉OpenSSL的童鞋應該知道使用openssl命令可以生成私鑰文件和對應的自簽名證書文件。

具體openssl的操作可以查看我的其他文章,這裏就不詳細講解了。

除了手動創建證書文件和私鑰文件之外,如果是在開發環境中,大家可能希望有一個非常簡單的方法來創建證書和私鑰文件,netty為大家提供了SelfSignedCertificate類。

看這個類的名字就是知道它是一個自簽名的證書類,並且會自動將證書文件和私鑰文件生成在系統的temp文件夾中,所以這個類在生產環境中是不推薦使用的。默認情况下該類會使用OpenJDK's X.509來生成證書的私鑰,如果不可以,則使用 Bouncy Castle作為替代。

netty中啟動SSL client

同樣的在client中支持SSL也需要創建一個handler。客戶端的SslContext創建代碼如下:

// 配置 SSL.
final SslContext sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();

上面的代碼我們使用了一個InsecureTrustManagerFactory.INSTANCE作為trustManager。什麼是trustManager呢?

當客戶端和服務器端進行SSL連接的時候,客戶端需要驗證服務器端發過來證書的正確性,通常情况下,這個驗證是到CA服務器中進行驗證的,不過這樣需要一個真實的CA證書環境,所以在測試中,我們使用InsecureTrustManagerFactory,這個類會默認接受所有的證書,忽略所有的證書异常。

當然,CA服務器也不是必須的,客戶端校驗的目的是查看證書中的公鑰和發送方的公鑰是不是一致的,那麼對於不能聯網的環境,或者自簽名的環境中,我們只需要在客戶端校驗證書中的指紋是否一致即可。

netty中提供了一個FingerprintTrustManagerFactory類,可以對證書中的指紋進行校驗。

該類中有個fingerprints數組,用來存儲安全的授權過的指紋信息。通過對比傳入的證書和指紋,如果一致則校驗通過。

使用openssl從證書中提取指紋的步驟如下:

openssl x509 -fingerprint -sha256 -in my_certificate.crt

總結

通過設置client和server端的SSL handler,就可以實現客戶端和服務器端的加密消息傳輸。

本文的例子可以參考:learn-netty4

本文已收錄於 http://www.flydean.com/12-netty-securechat/

最通俗的解讀,最深刻的幹貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!

版权声明:本文为[flydean]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815163547226w.html