OkHttp盡力去平衡兩個相互競爭的關注點:
- Connectivity:盡可能地連接更多地主機。這個包括運行boringssl最新版本的先進主機和運行OpenSSL老版本的稍微過時的主機。
- Security:連接的安全性。這個包括使用證書驗證遠程網絡服務器和使用強密碼的數據交換隱私。
當涉及到一個到HTTPS服務器的連接時,OkHttp需要知道提供哪個TLS版本和安全套件。一個客戶端想要最大化連通性會包含廢棄的TLS版本和weak-by-design密碼套件。一個嚴謹的客戶端想要最大化連通性會限制只能用最新TLS版本和最強的密碼套件。
特定的安全vs連通性決策通過ConnectionSpec實現。OkHttp包含三個內置的連接規格:
- MODERN_TLS:一個連接先進HTTPS服務器的安全配置。
- COMPATIBLE_TLS:一個連接安全但是非current-HTTPS服務器的安全配置。
- CLEARTEXT:一個用于http://的URL的不安全配置。
默認,OkHttp會嘗試MODERN_TLS連接,如果先進配置失敗,則會回退到COMPATIBLE_TLS連接。
TLS版本和加密套件的規格可能隨著每個版本改變。例如,在OkHttp2.2,我們放棄支持SSL3.0作為POODLE攻擊的響應。在OkHttp2.3放棄支持RC4.與你的桌面網絡瀏覽器一樣,保持OkHttp最新是保持安全的最好方式。
你可以使用一個自定義TLS版本和加密套件集構建你自己的連接規格。例如,這個配置限制了三種德高望重的加密套件。它的缺陷是需要Android5.0版本以上以及一個類似先進網路服務器。
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.build();
認證綁定
默認,OkHttp信任主機平臺的證書頒發機構。這個策略最大化了連通性,但是它也受限制于像2011 DigiNotar attack的證書頒發機構攻擊。它也假定你的HTTPS服務器證書也是由證書頒發機構簽署。
使用CertificatePinner來限制哪些證書和證書頒發機構可以被信任。證書鎖定提升安全性,但是限制你的服務器團隊更新他們的TLS證書的能力。如果沒有你的服務器的TLS管理員的祝福,不要使用證書鎖定!
public CertificatePinning() {
client = new OkHttpClient.Builder()
.certificatePinner(new CertificatePinner.Builder()
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.build())
.build();
}
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://publicobject.com/robots.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
for (Certificate certificate : response.handshake().peerCertificates()) {
System.out.println(CertificatePinner.pin(certificate));
}
}
自定義可信任證書機構
全部的代碼樣例展示了如果使用你自己的證書頒發機構替換主機的。跟上面一樣,如果沒有你的服務器的TLS管理員的祝福,不要使用證書鎖定!
private final OkHttpClient client;
public CustomTrust() {
SSLContext sslContext = sslContextForTrustedCertificates(trustedCertificatesInputStream());
client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.build();
}
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
private InputStream trustedCertificatesInputStream() {
... // Full source omitted. See sample.
}
public SSLContext sslContextForTrustedCertificates(InputStream in) {
... // Full source omitted. See sample.
}
原文鏈接:
https://github.com/square/okhttp/wiki/HTTPS
OkHttp官方文檔系列文章: