android 与 https

1.官方文档

android https https://developer.android.google.cn/training/articles/security-ssl  
android 配置ca  https://developer.android.google.cn/training/articles/security-config 自签名证书配置、network_security_config.xml语法等
okhttp  配置ca https://square.github.io/okhttp/https/#customizing-trusted-certificates-kt-java

2.android 上使用自签名证书

2.1 生成证书

  参考: https://www.cnblogs.com/sjjg/p/15327857.html

2.2 在代码中设置ca示例

  • HttpsURLConnection
     1 // Load CAs from an InputStream
     2     // (could be from a resource or ByteArrayInputStream or ...)
     3     val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
     4     // From https://www.washington.edu/itconnect/security/ca/load-der.crt
     5     val caInput: InputStream = BufferedInputStream(FileInputStream("load-der.crt"))
     6     val ca: X509Certificate = caInput.use {
     7         cf.generateCertificate(it) as X509Certificate
     8     }
     9     System.out.println("ca=" + ca.subjectDN)
    10 
    11     // Create a KeyStore containing our trusted CAs
    12     val keyStoreType = KeyStore.getDefaultType()
    13     val keyStore = KeyStore.getInstance(keyStoreType).apply {
    14         load(null, null)
    15         setCertificateEntry("ca", ca)
    16     }
    17 
    18     // Create a TrustManager that trusts the CAs inputStream our KeyStore
    19     val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
    20     val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
    21         init(keyStore)
    22     }
    23 
    24     // Create an SSLContext that uses our TrustManager
    25     val context: SSLContext = SSLContext.getInstance("TLS").apply {
    26         init(null, tmf.trustManagers, null)
    27     }
    28 
    29     // Tell the URLConnection to use a SocketFactory from our SSLContext
    30     val url = URL("https://certs.cac.washington.edu/CAtest/")
    31     val urlConnection = url.openConnection() as HttpsURLConnection
    32     urlConnection.sslSocketFactory = context.socketFactory
    33     val inputStream: InputStream = urlConnection.inputStream
    34     copyInputStreamToOutputStream(inputStream, System.out)
  • okhttp
     1 private val client: OkHttpClient
     2 
     3   init {
     4     val trustManager = trustManagerForCertificates(trustedCertificatesInputStream())
     5     val sslContext = SSLContext.getInstance("TLS")
     6     sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
     7     val sslSocketFactory = sslContext.socketFactory
     8 
     9     client = OkHttpClient.Builder()
    10         .sslSocketFactory(sslSocketFactory, trustManager)
    11         .build()
    12   }
    13 
    14   fun run() {
    15     val request = Request.Builder()
    16         .url("https://publicobject.com/helloworld.txt")
    17         .build()
    18 
    19     client.newCall(request).execute().use { response ->
    20       if (!response.isSuccessful) throw IOException("Unexpected code $response")
    21 
    22       for ((name, value) in response.headers) {
    23         println("$name: $value")
    24       }
    25 
    26       println(response.body!!.string())
    27     }
    28   }
    29 
    30   /**
    31    * Returns an input stream containing one or more certificate PEM files. This implementation just
    32    * embeds the PEM files in Java strings; most applications will instead read this from a resource
    33    * file that gets bundled with the application.
    34    */
    35   private fun trustedCertificatesInputStream(): InputStream {
    36     ... // Full source omitted. See sample.
    37   }
    38 
    39   private fun trustManagerForCertificates(inputStream: InputStream): X509TrustManager {
    40     ... // Full source omitted. See sample.
    41   }

3.android 应用内配置ca

  target <= 23 的应用默认情况下会信任用户添加的 CA ,应用可以在res/xml/network_security_config.xml 内,使用 

  • base-config(应用范围的自定义)
  • domain-config(针对每个域名的自定义)

  它的配置如下:

1     <base-config cleartextTrafficPermitted="true">
2         <trust-anchors>
3             <certificates src="system" />
4             <certificates src="user" />
5         </trust-anchors>
6     </base-config>

  当( 23 < target <= 27) 时,它的默认配置如下:

1      <base-config cleartextTrafficPermitted="true">
2          <trust-anchors>
3              <certificates src="system" />
4          </trust-anchors>
5      </base-config>

  当 target > 27时,cleartextTrafficPermitted="false" 表示不支持明文传输。

3.1 配置自定义 CA

1     <?xml version="1.0" encoding="utf-8"?>
2     <network-security-config>
3         <domain-config>
4             <domain includeSubdomains="true">example.com</domain>
5             <trust-anchors>
6                 <certificates src="@raw/my_ca"/>
7             </trust-anchors>
8         </domain-config>
9     </network-security-config>

证书 以 PEM 或 DER 格式。如果使用 PEM 格式,文件必须仅包含 PEM 数据,且没有额外的文本。

3.2 限制可信CA集

 1     <?xml version="1.0" encoding="utf-8"?>
 2     <network-security-config>
 3         <domain-config>
 4             <domain includeSubdomains="true">secure.example.com</domain>
 5             <domain includeSubdomains="true">cdn.example.com</domain>
 6             <trust-anchors>
 7                 <certificates src="@raw/trusted_roots1"/>
 8                 <certificates src="@raw/trusted_roots2"/>
 9                 ...
10             </trust-anchors>
11         </domain-config>
12     </network-security-config>

3.3 信任其他 CA

1     <?xml version="1.0" encoding="utf-8"?>
2     <network-security-config>
3         <base-config>
4             <trust-anchors>
5                 <certificates src="@raw/extracas"/>
6                 <certificates src="system"/>
7             </trust-anchors>
8         </base-config>
9     </network-security-config>

3.4 固定证书

一般情况下,应用信任所有预装 CA。如果有预装 CA 颁发了欺诈性证书,则应用将面临被中间人攻击的风险。有些应用选择通过限制信任的 CA 集或通过固定证书来限制其接受的证书集。

如需固定证书,您可以通过按公钥的哈希值(X.509 证书的 SubjectPublicKeyInfo)提供证书集。然后,只有至少包含一个已固定公钥的证书链才有效。

  详见 : https://developer.android.google.cn/training/articles/security-config#CertificatePinning

 1     <?xml version="1.0" encoding="utf-8"?>
 2     <network-security-config>
 3         <domain-config>
 4             <domain includeSubdomains="true">example.com</domain>
 5             <pin-set expiration="2018-01-01">
 6                 <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
 7                 <!-- backup pin -->
 8                 <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
 9             </pin-set>
10         </domain-config>
11     </network-security-config>

4.安全测试工具

  Nogotofai

    https://github.com/google/nogotofail

 

 

 

 

posted @ 2021-10-02 10:48  f9q  阅读(192)  评论(0编辑  收藏  举报