如何解决Gradle代码生成器中的CWE-297证书主机不匹配验证问题?
问题解释
CWE-297的核心是未正确校验服务器SSL证书中声明的主机名与实际连接的目标主机名是否一致,这会给中间人攻击敞开大门——攻击者可使用伪造的、主机名不匹配的证书冒充目标服务器,而你的代码会错误地通过验证。
你的代码里的问题出在!verifyingSsl分支的自定义HostnameVerifier实现:
hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return hostname.equals(session.getPeerHost()); } };
这个实现完全跳过了证书主机名的校验逻辑:hostname是你要连接的目标主机名,session.getPeerHost()本质也是该目标主机名,两者对比毫无意义,根本没去验证服务器证书里实际包含的主机名,这正是Veracode触发CWE-297告警的直接原因。
另外该分支下的X509TrustManager完全信任所有证书,会导致证书链验证也被跳过,属于另一类严重安全问题(CWE-295),生产环境绝对不能使用。
修复方法
方案1:移除不安全的跳过验证逻辑(推荐)
生产环境必须强制启用SSL验证(确保verifyingSsl始终为true),直接删除!verifyingSsl分支的代码,让所有请求都使用你代码里else分支的正确验证逻辑——基于系统信任库或自定义CA证书做证书链校验,同时用OkHostnameVerifier.INSTANCE做标准主机名校验。
方案2:测试环境需保留跳过逻辑时,修正主机名验证
如果是测试场景临时需要跳过部分验证,也不能保留当前无效的HostnameVerifier,至少要使用OkHttp提供的标准主机名验证器:
修正后的!verifyingSsl分支代码:
if (!verifyingSsl) { // 注意:此逻辑仅允许用于测试环境,生产环境禁止部署 trustManagers = new TrustManager[]{ new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } } }; // 替换为OkHttp标准主机名验证器,确保证书主机名与目标匹配 hostnameVerifier = OkHostnameVerifier.INSTANCE; }
这样至少会正确校验证书中的主机名是否与目标主机一致,解决CWE-297的问题。
额外提醒
哪怕是测试环境使用修正后的代码,也必须严格控制使用范围,绝对不能部署到生产环境。生产环境必须完全启用SSL证书链验证和主机名验证,保障通信安全。
内容的提问来源于stack exchange,提问作者Joanatas Barbosa

