TrustManager
接受所有证书¶
ID: java/insecure-trustmanager
Kind: path-problem
Security severity: 7.5
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-295
Query suites:
- java-code-scanning.qls
- java-security-extended.qls
- java-security-and-quality.qls
如果 TrustManager
的 checkServerTrusted
方法从不抛出 CertificateException
,则它会信任所有证书。这允许攻击者对应用程序执行中间人攻击,从而破坏传输层安全 (TLS) 提供的任何安全性。
攻击可能如下所示
易受攻击的程序连接到
https://example.com
。攻击者拦截此连接,并为
https://example.com
提供有效的自签名证书。易受攻击的程序调用
checkServerTrusted
方法以检查是否应该信任该证书。您的
TrustManager
的checkServerTrusted
方法不抛出CertificateException
。易受攻击的程序接受证书并继续连接,因为您的
TrustManager
通过不抛出异常而隐式地信任它。攻击者现在可以读取您的程序发送到
https://example.com
的数据,或在程序认为连接安全的情况下修改其回复。
建议¶
不要使用信任任何证书的自定义 TrustManager
。如果您必须使用自签名证书,不要信任所有证书,而只信任此特定证书。有关如何执行此操作的示例,请参见下文。
示例¶
在第一个(错误)示例中,TrustManager
永远不会抛出 CertificateException
,因此隐式地信任任何证书。这允许攻击者执行中间人攻击。在第二个(正确)示例中,要信任的自签名证书被加载到 KeyStore
中。这明确地定义了证书为可信的,并且不需要创建自定义 TrustManager
。
public static void main(String[] args) throws Exception {
{
class InsecureTrustManager implements X509TrustManager {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// BAD: Does not verify the certificate chain, allowing any certificate.
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
}
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] trustManager = new TrustManager[] { new InsecureTrustManager() };
context.init(null, trustManager, null);
}
{
SSLContext context = SSLContext.getInstance("TLS");
File certificateFile = new File("path/to/self-signed-certificate");
// Create a `KeyStore` with default type
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// `keyStore` is initially empty
keyStore.load(null, null);
X509Certificate generatedCertificate;
try (InputStream cert = new FileInputStream(certificateFile)) {
generatedCertificate = (X509Certificate) CertificateFactory.getInstance("X509")
.generateCertificate(cert);
}
// Add the self-signed certificate to the key store
keyStore.setCertificateEntry(certificateFile.getName(), generatedCertificate);
// Get default `TrustManagerFactory`
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Use it with our key store that trusts our self-signed certificate
tmf.init(keyStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
// GOOD, we are not using a custom `TrustManager` but instead have
// added the self-signed certificate we want to trust to the key
// store. Note, the `trustManagers` will **only** trust this one
// certificate.
URL url = new URL("https://self-signed.badssl.com/");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(context.getSocketFactory());
}
}
参考资料¶
Android 开发者:使用 HTTPS 和 SSL 保持安全.
常见漏洞枚举:CWE-295.