1 Introduction
數(shù)據(jù)安全在網(wǎng)絡(luò)通信中是非常重要的一個(gè)方面。為了支持 SSL/TLS权悟,Java 提供了 javax.net.ssl包下的類SslContext 和 SslEngine 砸王。在Netty框架下,I/O數(shù)據(jù)在ChannelPipeline
中被管道中的ChannelHandler
處理并轉(zhuǎn)發(fā)給下一個(gè)ChannelHandler
峦阁。自然而然地谦铃,Netty也提供了ChannelHandler
的實(shí)現(xiàn)SslHandler
來(lái)支持SSL, 有一個(gè)內(nèi)部 SslEngine 做實(shí)際的工作。
2 Steps
首先看看SslHandler
的構(gòu)造函數(shù):
public SslHandler(SSLEngine engine) {
this(engine, false);
}
public SslHandler(SSLEngine engine, boolean startTls) {
this(engine, startTls, ImmediateExecutor.INSTANCE);
}
不難發(fā)現(xiàn)榔昔,我們需要一個(gè)SSLEngine
對(duì)象來(lái)構(gòu)建SslHandler
驹闰。根據(jù)資料可以知道,需要根據(jù)已初始化的 SSLContext
來(lái)調(diào)用 SSLContext.createSSLEngine()
即可創(chuàng)建 SSLEngine
撒会。
所以基于Netty框架的在TCP連接中使用SSL/TLS加密的流程如下:
- 在代碼中導(dǎo)入證書嘹朗,并使用該證書構(gòu)造
SSLContext
- 調(diào)用
SSLContext
對(duì)象的createSSLEngine()
創(chuàng)建SSLEngine
- 用
SSLEngine
對(duì)象去初始化Netty的SslHandler
- 在Netty的
ChannelInitializer.initChannel()
中,往管道(pipeline)中安裝SslHandler
诵肛。
3 Usage
3.1 導(dǎo)入證書
public SSLContext getClientSSLContext(){
KeyStore trustKeyStore= KeyStore.getInstance("JKS");// 訪問(wèn)Java密鑰庫(kù)屹培,JKS是keytool創(chuàng)建的Java密鑰庫(kù)
InputStream keyStream = MyApplication.getAppContext().getAssets().open("key.jks");//打開(kāi)證書文件(.jks格式)
char keyStorePass[]="12345678".toCharArray(); //證書密碼
keyStore .load(trustKeyStore,keyStorePass);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore );//保存服務(wù)端的授權(quán)證書
SSLContext clientContext = SSLContext.getInstance( "TLS");
clientContext.init(null, trustManagerFactory.getTrustManagers(), null);
return clientContext;
}
在上述代碼,只是實(shí)現(xiàn)了client采用trustKeyStore中的key.jks證書(包含了server的公鑰)對(duì)數(shù)據(jù)解密,如果解密成功褪秀,證明消息來(lái)自server蓄诽,進(jìn)行邏輯處理。
僅僅是server->client單向的SSL認(rèn)證媒吗。
如果要實(shí)現(xiàn)server和client之間雙向的身份認(rèn)證仑氛,需要模仿trustManagerFactory
的初始化來(lái)構(gòu)建一個(gè)KeyManagerFactory
來(lái)其中保存客戶端的私鑰,并傳入
clientContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
3.2 添加 SslHandler
ChannelHandler在應(yīng)該初始化(ChannelInitializer.initChannel()
被調(diào)用時(shí))階段被安裝在ChannelPipeline中蝴猪。
Bootstrap的介紹參考Android開(kāi)發(fā)之使用Netty進(jìn)行Socket編程(二)
Boostrap的初始化參考Android開(kāi)發(fā)之使用Netty進(jìn)行Socket編程(三)
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
SSLEngine engine = getClientSSLContext().createSSLEngine();
engine.setUseClientMode(true);
pipeline.addFirst("ssl", new SslHandler(engine));
//....再添加其他的ChannelHandler
pipeline.addLast(nettyChannelHandler);
}
});
在大多數(shù)情況下,SslHandler 將成為 ChannelPipeline 中的第一個(gè) ChannelHandler调衰,所以調(diào)用了pipeline.addFirst()
。這將確保所有其他 ChannelHandler 應(yīng)用他們的邏輯到數(shù)據(jù)后加密后才發(fā)生,從而確保他們的變化是安全的自阱。