CodeQL 文档

Android 缺少证书固定

ID: java/android/missing-certificate-pinning
Kind: problem
Security severity: 5.9
Severity: warning
Precision: medium
Tags:
   - security
   - external/cwe/cwe-295
Query suites:
   - java-security-extended.qls
   - java-security-and-quality.qls

单击以在 CodeQL 存储库中查看查询

证书固定是一种仅信任特定一组 SSL 证书的做法,而不是设备默认信任的证书。在 Android 应用程序中,建议在通过网络进行通信时使用证书固定,以最大程度地降低来自受损 CA 的中间人攻击的风险。

建议

实现证书固定的最简单方法是在 network-security-config XML 文件中声明你的固定。这将自动为应用程序建立的任何网络连接提供证书固定。

实现证书固定的另一种方法是使用 `okhttp` 库中的 `CertificatePinner` 类。

实现证书固定的最后一种方法是使用 TrustManager,该管理器从仅加载有必要证书的 KeyStore 中初始化。

示例

在下面的第一个(错误)案例中,执行网络调用时未实现证书固定。其他(正确)案例演示了实现证书固定的不同方法。

// BAD - By default, this network call does not use certificate pinning
URLConnection conn = new URL("https://example.com").openConnection();
<!-- GOOD: Certificate pinning implemented via a Network Security Config file -->

<!-- In AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app">

    <application android:networkSecurityConfig="@xml/NetworkSecurityConfig">
        ...
    </application>

</manifest>

<!-- In res/xml/NetworkSecurityConfig.xml -->
<network-security-config>
    <domain-config>
        <domain>good.example.com</domain>
        <pin-set expiration="2038/1/19">
            <pin digest="SHA-256">...</pin>
        </pin-set>
    </domain-config>
</network-security-config>
// GOOD: Certificate pinning implemented via okhttp3.CertificatePinner 
CertificatePinner certificatePinner = new CertificatePinner.Builder()
    .add("example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(certificatePinner)
    .build();

client.newCall(new Request.Builder().url("https://example.com").build()).execute();



// GOOD: Certificate pinning implemented via a TrustManager
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(resources.openRawResource(R.raw.cert), null);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

URL url = new URL("http://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); 

urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私