Android中Https通訊實現_ 單向認證
阿新 • • 發佈:2018-12-27
客戶端與服務端單向認證即是在客戶端的網路請求和webview中設定信任所有證書,然後在與服務端進行Https網路通訊的時候,客戶端不必進行證書校驗也能進行網路通訊,否則就會報證書不受信異常。
缺陷:容易受到中間人攻擊。
概覽
- TrustManager和HostnameVerifier
- HttpURLConnection信任所有證書
- OkHttp信任所有證書
- webview信任所有證書
X509TrustManager
和HostnameVerifier
X509TrustManager用於實現SSL證書
的安全校驗,若使用不當,將導致APP對SSL證書不作校驗,從而 黑客有了中間人攻擊的可乘之機。開發者常見錯誤:
- 自定義X509TrustManager,且不做任何校驗邏輯,一般為空實現;
HostnameVerifier用於實現HTTPS通訊中的域名
安全校驗,即驗證當前連線的HTTPS站點的SSL證書中的域名是否等於站點本身的域名。開發者常見錯誤:
- 自定義HostnameVerifier,且不做任何校驗邏輯,一般為return true;
- 使用Android系統中自帶的不安全的HostnameVerifier,效果等同於不做任何校驗邏輯:
org.apache.http.conn.ssl.AllowAllHostnameVerifier
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLSocketClient {
//獲取這個SSLSocketFactory
public static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//獲取TrustManager
private static TrustManager[] getTrustManager() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// return null; 或者
return new X509Certificate[]{}; // 空實現
}
}
};
return trustAllCerts;
}
//獲取HostnameVerifier
public static HostnameVerifier getHostnameVerifier() {
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
// true表示信任所有域名
return true;
}
};
return hostnameVerifier;
}
}
使用Android系統中自帶的不安全的HostnameVerifie
URL url = new URL("https url");
HttpsURLConnection conn= (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpURLConnection
信任所有證書
URL url = new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestType);
conn.setConnectTimeout(timeOut * 1000);
// 配置https的證書
if ("https".equalsIgnoreCase(url.getProtocol())){
((HttpsURLConnection) conn).setSSLSocketFactory(SSLSocketClient.getSSLSocketFactory());
((HttpsURLConnection) conn).setHostnameVerifier(SSLSocketClient.getHostnameVerifier());
}
OkHttp
信任所有證書
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
.hostnameVerifier(SSLSocketClient.getHostnameVerifier())
.build();
webview
信任所有證書
Android系統內建了一些可信機構辦法的證書,可用於作HTTPS證書校驗。實際上,使用Webview元件進HTTPS通訊,其證書驗證環節也是系統預設會去做的。若發現證書不合法,Webview將顯示一個空白頁面,其錯誤在onReceivedSslError()這個方法裡進行處理。
在WebViewClient原始碼中可以看到系統預設處理,是拒絕連線帶有可信機構頒發證書的HTTPS站點的,如下所示:
/**
* Notify the host application that an SSL error occurred while loading a
* resource. The host application must call either handler.cancel() or
* handler.proceed(). Note that the decision may be retained for use in
* response to future SSL errors. The default behavior is to cancel the
* load.
*
* @param view The WebView that is initiating the callback.
* @param handler An SslErrorHandler object that will handle the user's
* response.
* @param error The SSL error object.
*/
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
// 拒絕連線
handler.cancel();
}
而我們重寫此方法的時候可以設定成接受所有連線,如下所示:
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
// 接受所有連線
handler.proceed();
}
參考:
https://blog.csdn.net/jogger_ling/article/details/60576625
https://blog.csdn.net/u012852986/article/details/78873387
https://blog.csdn.net/Hubert_bing/article/details/55258280