1.Https相關知識
1.1 http與https的區別
HTTP協議傳輸的資料都是未加密的,也就是明文的,因此使用HTTP協議傳輸隱私資訊非常不安全,為了保證這些隱私資料能加密傳輸,於是網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的資料進行加密,從而就誕生了HTTPS。簡單來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,要比http協議安全。
HTTPS和HTTP的區別主要如下:
-
https協議需要到ca申請證照,一般免費證照較少,因而需要一定費用。
-
http是超文字傳輸協議,資訊是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
-
http和https使用的是完全不同的連線方式,用的埠也不一樣,前者是80,後者是443。
-
http的連線很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網路協議,比http協議安全。
1.2 Https的優點
-
認證使用者和伺服器,確保資料傳送到正確的客戶機和伺服器;(驗證證照)
-
加密資料以防止資料中途被竊取;(加密)
-
維護資料的完整性,確保資料在傳輸過程中不被改變。(摘要演算法)
2.Okhttp中使用自簽名證照
一般支援https的網站,都是CA(Certificate Authority)機構頒發的證照,但是一般該機構頒發的證照需要提供費用且有使用時間的限制,到期需要續費。否則預設該連結是不信任的,通過okHttp無法直接訪問。
但是我們可以使用自籤的方式,通過JDK自帶的keytool.exe 生成一個自己的證照,然後使用該證照內容。雖然也是會出現提示“不安全”,但是我們可以通過okhttp訪問連結。
2.1 使用自簽證照
將證照檔案放置在assets目錄(也可以放置在其他目錄下,只要能正確讀取到該檔案),在建立OkhttpClient物件時sslSocketFactory()將該證照資訊新增。
private SSLContext getSLLContext() {
SSLContext sslContext = null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream certificate = mContext.getAssets().open("gdroot-g2.crt");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
String certificateAlias = Integer.toString(0);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
sslContext = SSLContext.getInstance("TLS");
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslContext;
}
複製程式碼
通過以上程式碼可以看出,通過InputStream方式讀取證照資訊,因此為了避免將證照檔案打包到APK中,我們可以直接將證照檔案內容放置在String中,將該字串轉為流的形式。
在使用okhttp時,將其設定到sslSocketFactory中。
OkHttpClient httpClient = new OkHttpClient().newBuilder()
.sslSocketFactory(getSLLContext().getSocketFactory())
.build();
複製程式碼
2.2 信任所有證照
通過新增證照的形式,可以實現客戶端訪問Https服務端的功能,但是如果服務端更換證照內容,那麼客戶端需要相應的更換https證照,否則無法正常互動獲取不到資料,我們可以通過自定義X509TrustManager的形式實現來規避所有的證照檢測,實現信任所有證照的目的。
private OkHttpClient getHttpsClient() {
OkHttpClient.Builder okhttpClient = new OkHttpClient().newBuilder();
//信任所有伺服器地址
okhttpClient.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
//設定為true
return true;
}
});
//建立管理器
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] x509Certificates,
String s) throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] x509Certificates,
String s) throws java.security.cert.CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
} };
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
//為OkHttpClient設定sslSocketFactory
okhttpClient.sslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
return okhttpClient.build();
}
複製程式碼
建立X509TrustManager物件,並實現其中的方法,由於X509TrustManager是通用證照格式,只需要拿到該格式就行。最後init該安全協議,將其放入okhttp的sslSocketFactory中。 由於Retrofit只是對Okhttp網路介面的封裝,因此實際使用中,該方法同樣適用於Retrofit中。