OkHttp试图平衡两个相互竞争的关注点:

  • 连接到尽可能多的主机。这包括运行最新版本boringssl的高级主机,以及运行旧版本OpenSSL的少数过时的主机。
  • 连接的安全性。这包括使用证书验证远程web服务器,以及使用强大的密码体系保证交换数据的隐私性。

在与HTTPS服务器的连接时,OkHttp需要知道要提供哪些TLS版本和密码套件。客户端想要最大限度地连接服务器,不得不包括过时的TLS版本和设计不足的密码套件。一个想要最大限度地提高安全性的严格客户端将仅限于最新的TLS版本和最强的密码套件。

具体的安全性与连接性决策由ConnectionSpec实现。OkHttp包括四个内置连接规格:

  • RESTRICTED_TLS是一个安全的配置,目的是满足更严格的遵从性要求。
  • MODERN_TLS是一个连接到现代HTTPS服务器的安全配置。
  • COMPATIBLE_TLS是一种安全配置,可以连接到安全但不是当前的Https服务器。
  • CLEARTEXT是一个不安全的配置,用于http:// url。

它们大致遵循谷歌云策略中设置的模型。

默认情况下,OkHttp将尝试一个MODERN_TLS连接。然而,通过配置客户端connectionSpecs,如果现代配置失败,您可以允许返回到COMPATIBLE_TLS连接。

OkHttpClient client = new OkHttpClient.Builder() .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)).build();

每个规范中的TLS版本和密码套件可以随着每个版本的不同而改变。例如,在OkHttp 2.2中,为了应对POODLE 攻击,我们放弃了对SSL 3.0的支持。在OkHttp 2.3中,我们放弃了对RC4的支持。与桌面web浏览器一样,使用OkHttp是保持安全的最佳方法。

您可以使用一组自定义的TLS版本和密码套件构建自己的连接规范。例如,这个配置仅限于三个备受关注的密码套件。它的缺点是需要Android 5.0+和一个类似的当前webserver。

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管理员的许可,不要使用固定证书!

import java.io.IOException;
import java.security.cert.Certificate;
import okhttp3.CertificatePinner;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;public final class CertificatePinning {private final OkHttpClient client;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();try (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));}}}public static void main(String... args) throws Exception {new CertificatePinning().run();}
}

自定义证书

完整的代码示例展示了如何用您自己的集合替换主机平台的证书颁发机构。如上所述,如果没有服务器的TLS管理员的许可,不要使用自定义证书!

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Collection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.CertificatePinner;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okio.Buffer;public final class CustomTrust {private final OkHttpClient client;public CustomTrust() {X509TrustManager trustManager;SSLSocketFactory sslSocketFactory;try {trustManager = trustManagerForCertificates(trustedCertificatesInputStream());SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(null, new TrustManager[] { trustManager }, null);sslSocketFactory = sslContext.getSocketFactory();} catch (GeneralSecurityException e) {throw new RuntimeException(e);}client = new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, trustManager).build();}public void run() throws Exception {Request request = new Request.Builder().url("https://publicobject.com/helloworld.txt").build();try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);Headers responseHeaders = response.headers();for (int i = 0; i < responseHeaders.size(); i++) {System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));}System.out.println(response.body().string());}}/*** Returns an input stream containing one or more certificate PEM files. This implementation just* embeds the PEM files in Java strings; most applications will instead read this from a resource* file that gets bundled with the application.*/private InputStream trustedCertificatesInputStream() {// PEM files for root certificates of Comodo and Entrust. These two CAs are sufficient to view// https://publicobject.com (Comodo) and https://squareup.com (Entrust). But they aren't// sufficient to connect to most HTTPS sites including https://godaddy.com and https://visa.com.// Typically developers will need to get a PEM file from their organization's TLS administrator.String comodoRsaCertificationAuthority = ""+ "-----BEGIN CERTIFICATE-----\n"+ "MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n"+ "hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n"+ "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n"+ "BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\n"+ "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n"+ "EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n"+ "Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\n"+ "dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n"+ "6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\n"+ "pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n"+ "9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n"+ "/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\n"+ "Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n"+ "+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\n"+ "qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\n"+ "SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\n"+ "u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\n"+ "Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\n"+ "crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n"+ "FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n"+ "/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\n"+ "wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n"+ "4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n"+ "2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\n"+ "FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\n"+ "CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\n"+ "boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\n"+ "jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\n"+ "S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\n"+ "QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n"+ "0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\n"+ "NVOFBkpdn627G190\n"+ "-----END CERTIFICATE-----\n";String entrustRootCertificateAuthority = ""+ "-----BEGIN CERTIFICATE-----\n"+ "MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC\n"+ "VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0\n"+ "Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW\n"+ "KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl\n"+ "cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw\n"+ "NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw\n"+ "NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy\n"+ "ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV\n"+ "BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\n"+ "KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo\n"+ "Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4\n"+ "4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9\n"+ "KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI\n"+ "rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi\n"+ "94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB\n"+ "sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi\n"+ "gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo\n"+ "kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\n"+ "vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\n"+ "A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t\n"+ "O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua\n"+ "AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP\n"+ "9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/\n"+ "eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m\n"+ "0vdXcDazv/wor3ElhVsT/h5/WrQ8\n"+ "-----END CERTIFICATE-----\n";return new Buffer().writeUtf8(comodoRsaCertificationAuthority).writeUtf8(entrustRootCertificateAuthority).inputStream();}/*** Returns a trust manager that trusts {@code certificates} and none other. HTTPS services whose* certificates have not been signed by these certificates will fail with a {@code* SSLHandshakeException}.** <p>This can be used to replace the host platform's built-in trusted certificates with a custom* set. This is useful in development where certificate authority-trusted certificates aren't* available. Or in production, to avoid reliance on third-party certificate authorities.** <p>See also {@link CertificatePinner}, which can limit trusted certificates while still using* the host platform's built-in trust store.** <h3>Warning: Customizing Trusted Certificates is Dangerous!</h3>** <p>Relying on your own trusted certificates limits your server team's ability to update their* TLS certificates. By installing a specific set of trusted certificates, you take on additional* operational complexity and limit your ability to migrate between certificate authorities. Do* not use custom trusted certificates in production without the blessing of your server's TLS* administrator.*/private X509TrustManager trustManagerForCertificates(InputStream in)throws GeneralSecurityException {CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);if (certificates.isEmpty()) {throw new IllegalArgumentException("expected non-empty set of trusted certificates");}// Put the certificates a key store.char[] password = "password".toCharArray(); // Any password will work.KeyStore keyStore = newEmptyKeyStore(password);int index = 0;for (Certificate certificate : certificates) {String certificateAlias = Integer.toString(index++);keyStore.setCertificateEntry(certificateAlias, certificate);}// Use it to build an X509 trust manager.KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());keyManagerFactory.init(keyStore, password);TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {throw new IllegalStateException("Unexpected default trust managers:"+ Arrays.toString(trustManagers));}return (X509TrustManager) trustManagers[0];}private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {try {KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());InputStream in = null; // By convention, 'null' creates an empty key store.keyStore.load(in, password);return keyStore;} catch (IOException e) {throw new AssertionError(e);}}public static void main(String... args) throws Exception {new CustomTrust().run();}
}

本文是翻译文章,英文原文地址:https://github.com/square/okhttp/wiki/HTTPS

深入理解OkHttp3:(六)Https相关推荐

  1. 我是这样理解HTTP和HTTPS区别的

    为何要用https? http协议的缺点 通信使用明文,内容可能被窃听(重要密码泄露) 不验证通信方身份,有可能遭遇伪装(跨站点请求伪造) 无法证明报文的完整性,有可能已遭篡改(运营商劫持) 用htt ...

  2. okhttp3发送https请求

    okhttp工具类: package com.test.testdemo;import android.content.Context; import android.os.Bundle; impor ...

  3. 点云网络的论文理解(六)-Frustum PointNets 总体概括

    这里的总结一下: 1.解决什么总体问题:解决三维空间中的目标识别,最终结果是用一个小盒子也就是bounding box把这个东西框起来. 2.解决什么痛点 :1.原有的方案中忽略了三维最原始的特性.2 ...

  4. 通过OKhttp3 访问 https地址

    /*** okHttp3添加信任所有证书** @return*/public static OkHttpClient getUnsafeOkHttpClient() {try {final Trust ...

  5. TensorFlow从入门到理解(六):可视化梯度下降

    运行代码: import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.m ...

  6. 深入理解Camera 六(硬件抽象层实现)

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.概览 二.基本组件概念 三.组件结构关系 四.关键流程详解 相机硬件抽象层实现 一.概览 回顾高通平 ...

  7. fegin需要实现类_深入理解JVM(六)--虚拟机类加载机制

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类从被加载到虚拟机内存开始,到卸载出内存为止 ...

  8. 【深入理解JVM 六】虚拟机字节码执行系统

    前边几篇Blog分别介绍了JVM的类加载机制.运行时数据区域,那么字节码文件已然被加载到了JVM的内存中来,接下来就是执行它了.虚拟机字节码执行引擎的位置如下图所示,除了本地方法栈,其他运行时数据区域 ...

  9. 【深入理解CLR 六】基元类型、引用类型和值类型

    最近工作的事情比较忙,导致CLR很久没有更新了,恰巧周五听了涛涛的关于GC和内存管理的技术分享,想了下自己对CLR的学习得跟上,另外之前武哥推荐了一本书叫<码农翻身>,是一个IBM架构师写 ...

最新文章

  1. Linux2.6内核中链表的实现
  2. 网络营销外包新策略——B站坚信求新求变才能得以“青春永驻”!
  3. 7-5 密码锁 (10 分)
  4. 【剑指offer】面试题63:股票的最大利润(Java)
  5. python3 os_Python3 标准库:os
  6. 深度学习-CNN提取图像特征
  7. tocmat linux搭建测试环境,Apache+Tomcat 环境搭建(JK部署过程)
  8. 我的成长日记20210406(日常测试工作安排)
  9. 智慧小区智能物业管理系统综合解决方案
  10. 分布式一致性—Paxos算法
  11. unity使用Curvy随机选择路线
  12. 【WIN问题】微软Microsoft onenote/store 无法连接网络无法同步解决
  13. openwrt 程序C++ hello world的ipk软件包(三)
  14. 七、项目沟通管理(输入/工具与技术/输出)
  15. win10自带输入法突然变成了繁体
  16. 阿里达摩院发布并开源“通义”大模型,AI底座之上促场景创新
  17. 文件搜索工具(Python实现)
  18. duilib学习------网易云信combo控件
  19. nn.Sequential与nn.ModuleList
  20. 好烦哦,第12次双11全球大考,又考第一了

热门文章

  1. [玩转北京] 北京最值得你一看的博物馆大全
  2. 实习渗透工程师面试记录
  3. 旷世科技面试——CV岗/后端开发
  4. 2022 极术通讯-安谋科技迎来发展新机遇
  5. 阿里ET大脑如何帮助养猪产业提升PSY从20到32?
  6. 电磁场与电磁波_您的大脑在电磁场上
  7. chr 13 java 替换_Java ROT13编码转换算法实现
  8. 基于SSH的校园网上订餐系统
  9. 读 《异类》—马尔科姆·格拉德威尔 文摘
  10. 输入关键词获取今日头条免费图片