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
证书固定是一种仅信任特定一组 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());
参考¶
OWASP 移动安全:测试自定义证书存储和证书固定 (MSTG-NETWORK-4)。
Android 开发人员:网络安全配置。
OkHttp:CertificatePinner。
常见弱点枚举:CWE-295。