SAKA'S BLOG

OkHttp(五)之HTTPS

这一片翻译的很不怎么样,因为我不懂https协议,我不是搞服务器的也不是前端的。

OkHttp尝试平衡两个竞争的焦点:

  • 连接到尽可能多的主机。其中包括运行最新版本的boringssl的高级主机和运行旧版本的OpenSSL的较少过时的主机。
  • 连接的安全性。这包括使用证书和使用强密码交换的数据的隐私来验证远程Web服务器。

当与HTTPS服务器的连接时,OkHttp需要知道提供哪些TLS版本和密码套件。想要最大程度地提高连接性的客户端,那么他讲提供将包括过时的TLS版本和弱设计密码套件。要求最大化安全性的严格客户端将仅限于最新的TLS版本和最强的密码套件。

  • MODERN_TLS是一种连接到现代HTTPS服务器的安全配置。
  • COMPATIBLE_TLS是一种连接到安全但不是当前HTTPS服务器的安全配置。
  • CLEARTEXT是用于http://URL 的不安全配置。

默认情况下,OkHttp将尝试一个MODERN_TLS连接,如果现代配置失败,则回退到COMPATIBLE_TLS连接。

每个规范中的TLS版本和密码套件可以随每个版本而变化。例如,在OkHttp 2.2中,我们放弃了对SSL 3.0的支持,以响应POODLE攻击。在OkHttp 2.3中,我们放弃了对RC4的支持。与您的桌面网络浏览器,保持最新与OkHttp是保持安全的最佳方式。

您可以使用一组自定义的TLS版本和密码套件来构建您自己的连接规范。例如,该配置限于三个高度重视的密码套件。它的缺点是它需要Android 5.0+和类似的当前网络服务器。

1
2
3
4
5
6
7
8
9
10
11
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攻击。攻击还会假定您的HTTPS服务器的证书由证书颁发机构签名。

使用CertificatePinner来限制哪些证书和证书颁发机构受信任。 证书锁定提高了安全性,但限制了服务器团队更新其TLS证书的能力。 如果没有服务器的TLS管理员的祝福,请不要使用证书锁定!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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管理员的祝福,请不要使用自定义证书!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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.
}