title: Netty SSL安全配置
date: 2017-08-26 14:51:43
categories: 網絡安全
tags: [netty,ssl]
Netty SSL安全配置
摘要
在研發平台的過程中,涉及到平台網關和前置agent的通信加密,雖然目前軟件在內網中,但是由於平台和agent的特殊性,一旦被控制,部署的軟件就會受到很大威脅,平台網關采用Netty開發,下面主要介紹一下netty的ssl配置和安全軟件掃出的Diffie-Hellman弱密碼問題解決方法
主要名詞解釋
| 英文名稱或縮寫 | 名詞解釋 |
|-
| Netty | 高性能服務器端編程框架 |
| OpenSSL | 安全套接字層密碼庫 |
| KeyTool | 密鑰和證書管理工具 |
| Diffie-Hellman | 密鑰交換算法 |
SSL常用認證方式介紹
- 單向認證
- 雙向認證
- CA認證
SSL單向認證
單向認證只需客戶端驗證服務端,即客戶端只需要認證服務端的合法性,服務端不需要。這種認證方式適用Web應用,因為web應用的用戶數目廣泛,且無需在通訊層對用戶身份進行驗證,一般都在應用邏輯層來保證用戶的合法登入。但如果是企業應用對接,情況就不一樣,可能會要求對客戶端(相對而言)做身份驗證。這時就需要做SSL雙向認證。
SSL雙向認證
雙向認證顧名思義,服務端也需要認證客戶端的合法性,這就意味着客戶端的自簽名證書需要導入服務端的數字證書倉庫。
采用這種方式會不太便利,一但客戶端或者服務端修改了秘鑰和證書,就需要重新進行證書交換,對於調試和維護工作量非常大,並且由於agent數目不確定,動態增加agent的時候需要平台和agent雙發互相加入相應各自的證書。
CA認證
CA認證的好處是只要服務端和客戶端只需要將CA證書導入各自的keystore,客戶端和服務端只需判斷這些證書是CA簽名過的即可,這也是蜂鳥平台內部采用的認證方式
生成證書
openSSL的安裝不是本經驗案例的重點,這里不介紹
根證書生成
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout root.key –out root.crt –subj /C=CN/ST=ZheJiang/L=HangZhou/O=MyCompany/OU=GA/CN=GA –config openssl.cnf
服務器端證書生成
服務器端秘鑰對生成
keytool -genkey -alias server -keypass **** -validity 1825 -keyalg RSA -keystore gateway.keystore -keysize 2048 -storepass **** -dname "CN=GA, OU=GA, O=MyCompany, L=HangZhou, ST=ZheJiang, C=CN"
keypass: 指定生成秘鑰的密碼
keystore:指定存儲文件的密碼,再次打開需要此密碼
生成證書簽名請求
keytool -certreq -alias server -keystore gateway.keystore -validity 1825 -file gateway.csr -storepass ****
用根證書私鑰進行簽名
openssl x509 -req -in gateway.csr -CA root.crt -CAkey root.key -CAcreateserial -out gateway.pem -days 1825 -extensions SAN -extfile san1.cnf
導入根證書
keytool -keystore gateway.keystore -importcert -alias CA -file root.crt -storepass **** -noprompt
導入服務端證書
keytool -keystore gateway.keystore -importcert -alias server -file gateway.pem -storepass ****
客戶端證書生成方法與服務端基本相同,此處不再贅述,需要注意一點的是簽名根證書必須是同一個
Netty SSL配置
獲取SSLContext
public class SslContextFactory {
private static final String PROTOCOL = "TLS";
private static volatile SSLContext SERVER_CONTEXT = null;
private static final String DEFAULT_PROPERTIES = "application.properties";
private static final String KEYSTORE_TYPE = "server.ssl.key-store-type";
private static final String KEYSTORE_PASSWORD = "gateway.ssl.key-store-password";
private static final String GATEWAY_KEYSTORE = "gateway.ssl.key-store";
private SslContextFactory() {
}
private static void init(){
Properties properties = null;
InputStream gatewayKeyStore = null;
InputStream gatewayTrustStore = null;
try {
properties = PropertiesTool.getInstance().getProperties(DEFAULT_PROPERTIES, false);
//初始化keyManagerFactory
KeyStore ks = KeyStore.getInstance(properties.getProperty(KEYSTORE_TYPE));
gatewayKeyStore = new FileInputStream(properties.getProperty(GATEWAY_KEYSTORE));
ks.load(gatewayKeyStore, properties.getProperty(KEYSTORE_PASSWORD).toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, properties.getProperty(KEYSTORE_PASSWORD).toCharArray());
//初始化TrustManagerFacotry
KeyStore ts = KeyStore.getInstance(properties.getProperty(KEYSTORE_TYPE));
gatewayTrustStore = new FileInputStream(properties.getProperty(GATEWAY_KEYSTORE));
ts.load(gatewayTrustStore, properties.getProperty(KEYSTORE_PASSWORD).toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
//生成SSLContext
SERVER_CONTEXT = SSLContext.getInstance(PROTOCOL);
SERVER_CONTEXT.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (IOException e) {
throw new GatewayException(e.getMessage(), e);
} catch (Exception e) {
throw new GatewayException(e.getMessage(), e);
} finally {
if (null != gatewayKeyStore) {
try {
gatewayKeyStore.close();
} catch (IOException e) {
}
}
if (null != gatewayTrustStore) {
try {
gatewayTrustStore.close();
} catch (IOException e) {
}
}
}
}
public static SSLContext getServerContext() {
if(SERVER_CONTEXT == null){
synchronized (SslContextFactory.class) {
if (SERVER_CONTEXT == null) {
init();
}
}
}
return SERVER_CONTEXT;
}
}
加入NettyHandler
Netty 提供了一個SslHandler,主要用於加密和解密
在大多數情況下,SslHandler 將成為 ChannelPipeline 中的第一個 ChannelHandler 。這將確保所有其他 ChannelHandler 應用他們的邏輯到數據后加密后才發生,從而確保他們的變化是安全的。
圖片來自網絡
SSLContext sslCtx = SslContextFactory.getServerContext();
SSLEngine sslEngine = sslCtx.createSSLEngine();
//設置加密套件
sslEngine.setEnabledCipherSuites(Constants.CIPHER_ARRAY);
sslEngine.setUseClientMode(false);
sslEngine.setNeedClientAuth(true);
pipeline.addLast("SslEstablish",new SslHandler(sslEngine));
Diffie-Hellman 密碼過弱問題
研究人員Alex Halderman和Nadia Heninger提出NSA已經能夠通過攻擊1024位素數的Diffie-Hellman密鑰交換算法解密大量HTTPS、SSH和VPN連接。
提供安全的加密算法
public static final String[] CIPHER_ARRAY = {"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"};
參考資料
Netty權威指南
https://weakdh.org/sysadmin.html