原文:https://github.com/square/okhttp/wiki/HTTPS
下面是翻译:
安全超文本传输协议(HTTPS)
OkHttp试图平衡两个竞争的关注点:
l 连接尽可能多的主机。 这包括运行最新版本的boringssl的高级主机,以及运行较早版本的OpenSSL的较少旧的主机。
l 连接的安全性。这包括使用证书验证远程Web服务器,并使用强密码交换隐私的数据。
当协商与HTTPS服务器的连接时,OkHttp需要知道应该提供哪些TLS版本和密码套件。 想要最大化连接的客户端将包括过时的TLS版本和弱设计的密码套件。 希望最大化安全性的严格客户端将仅限于最新的TLS版本和最强的密码套件。
特定安全性与连接性决定由ConnectionSpec实现。 OkHttp包含三个内置的连接规范:
l MODERN_TLS是连接到现代HTTPS服务器的安全配置。
l COMPATIBLE_TLS是连接到安全但不是当前HTTPS服务器的安全配置。
l CLEARTEXT是用于http://URL的不安全配置。
默认情况下,OkHttp将尝试使用MODERN TLS连接,并返回到兼容TLS现代配置的TLS如果连接失败的话。
每个规范中的TLS版本和密码套件可随每个版本而更改。例如,在OkHttp 2.2中,我们放弃了对SSL 3.0的支持,以应对POODLE攻击。 而在OkHttp 2.3中,我们放弃了对RC4的支持。 与您的桌面网络浏览器一样,保持最新的OkHttp是保持安全的最佳方式。
您可以使用自定义的一组TLS版本和密码套件来构建自己的连接规范。例如,这种配置仅限于三个受人尊敬的密码套件。 它的缺点是它需要Android 5.0+和类似的当前网络服务器。
ConnectionSpec spec = newConnectionSpec.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 = newOkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.build();
证书限定
默认情况下,OkHttp信任主机平台的证书颁发机构。这种策略最大限度地提高了连接性,但是它受到诸如2011 DigiNotar攻击等认证机构的攻击。 它还假设您的HTTPS服务器的证书由证书颁发机构签署。
使用CertificatePinner限制哪些证书和证书颁发机构被信任。证书限定提高了安全性,但限制了您的服务器团队更新其TLS证书的能力。 不要在没有服务器的TLS管理员的管理的情况下使用证书限制!
public CertificatePinning()
{
client = new OkHttpClient.Builder()
.certificatePinner(newCertificatePinner.Builder()
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.build())
.build();
}
public void run() throwsException
{
Request request = new Request.Builder()
.url("https://publicobject.com/robots.txt")
.build();
Response response =client.newCall(request).execute();
if (!response.isSuccessful()) throw newIOException("Unexpected code " + response);
for (Certificate certificate :response.handshake().peerCertificates())
{
System.out.println(CertificatePinner.pin(certificate));
}
}
自定义受信任的证书
完整的代码示例显示如何使用您自己的集合替换主机平台的证书颁发机构。 如上所述,不要在没有服务器的TLS管理员的管理下使用自定义证书!
private final OkHttpClientclient;
public CustomTrust()
{
SSLContext sslContext =sslContextForTrustedCertificates(trustedCertificatesInputStream());
client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.build();
}
public void run() throwsException
{
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 InputStreamtrustedCertificatesInputStream()
{
... // Full source omitted. See sample.
}
public SSLContextsslContextForTrustedCertificates(InputStream in)
{
... // Full source omitted. See sample.
}