1. 背景與需求
近期在做IP切換的HTTPS訪問時(shí),遇到了一些問題:客戶端如何進(jìn)行HTTPS的證書驗(yàn)證塔嬉。
其實(shí)對(duì)于一般的項(xiàng)目基本都是做的單向驗(yàn)證阳惹,即在客戶端證書或者HOST的驗(yàn)證;對(duì)于金融晰筛、銀行相關(guān)的項(xiàng)目才會(huì)使用的雙向驗(yàn)證嫡丙,客戶端與服務(wù)端之間都要對(duì)彼此進(jìn)行驗(yàn)證,以防止中間人進(jìn)行攻擊读第。
2.實(shí)現(xiàn)目標(biāo)
本文記錄的是:客戶端實(shí)現(xiàn)對(duì)HOST的驗(yàn)證曙博,這樣基本滿足一般項(xiàng)目的需求,也不需要客戶端內(nèi)置證書卦方,引起更新時(shí)候的麻煩羊瘩。
3. 實(shí)現(xiàn)過程
- 實(shí)現(xiàn)SSLSocketFactory ,獲取SSLContext
我們這里沒有本地的證書,所以都是生成TrustManager 時(shí)都是空實(shí)現(xiàn),如果需要通過內(nèi)置證書來驗(yàn)證可以柴查看下面的鏈接尘吗。
public class SSLSocketFactoryImp extends SSLSocketFactory {
private SSLContext sslContext = SSLContext.getInstance("TLS");
private TrustManager trustManager = null;
public SSLContext getSSLContext() {
return sslContext;
}
public X509TrustManager getTrustManager() {
return (X509TrustManager)trustManager;
}
public SSLSocketFactoryImp(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException {
trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] x509Certificates = new X509Certificate[0];
return x509Certificates;
}
};
sslContext.init(null, new TrustManager[]{trustManager}, null);
}
@Override
public String[] getDefaultCipherSuites() {
return new String[0];
}
@Override
public String[] getSupportedCipherSuites() {
return new String[0];
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
@Override
public Socket createSocket(Socket socket, String host, int post, boolean autoClose) throws IOException {
return sslContext.getSocketFactory().createSocket(socket, host, post, autoClose);
}
@Override
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return null;
}
@Override
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
return null;
}
@Override
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return null;
}
@Override
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
return null;
}
}
- 關(guān)鍵步驟:驗(yàn)證HOST
這里是基于OKHTTP來進(jìn)行的驗(yàn)證操作,主要依靠:HttpsURLConnection.getDefaultHostnameVerifier().verify("你的域名", session)方法來驗(yàn)證域名是否一致
KeyStore trustStore;
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactoryImp ssl = new SSLSocketFactoryImp(KeyStore.getInstance(KeyStore.getDefaultType()));
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
boolean verify = HttpsURLConnection.getDefaultHostnameVerifier().verify("你的域名", session);
return verify;
}
};
builder.sslSocketFactory(ssl.getSSLContext().getSocketFactory(), ssl.getTrustManager()).hostnameVerifier
(hostnameVerifier);
4.一定要閱讀的文章
上面只是簡單的記錄驗(yàn)證HOST的方式逝她,下面的文章會(huì)讓你收獲更多。
1. 阿里移動(dòng)安全:Android安全開發(fā)之安全使用HTTPS