java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java SSL证书错误

Java SSL证书错误:No subject alternative names present的解决方案

作者:济南大胖子

本文深入解析Java SSL证书错误'No subject alternative names present'的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. 为什么会出现"No subject alternative names present"错误?

当你用Java程序通过HTTPS访问某个网站时,突然蹦出"java.security.cert.CertificateException: No subject alternative names present"这个错误,十有八九是因为SSL证书配置出了问题。这个错误的核心在于证书缺少主题备用名称(Subject Alternative Names,简称SANs),而现代Java安全机制强制要求验证这个字段。

简单来说,SANs就像是一张身份证上的多个身份信息。传统的SSL证书只认**Common Name(CN)**字段,就像身份证上只写了一个名字。但现实情况是,一个网站可能有多个域名(比如example.com和www.example.com),甚至需要支持IP地址直接访问。这时候就需要SANs来记录所有这些合法的访问方式。

我在实际项目中遇到过这样一个案例:开发团队为内部测试环境配置了HTTPS,用OpenSSL生成了自签名证书,只填写了CN字段。结果用Java程序调用接口时,就遇到了这个经典错误。后来发现是因为JDK 1.8之后加强了对SANs的校验,而他们生成的证书没有包含这个扩展字段。

2. 深入理解SANs的工作原理

2.1 SANs与CN字段的历史演变

早期SSL/TLS证书验证主要依赖CN字段,但随着互联网发展,这种单一标识的方式暴露出了明显缺陷:

SANs扩展就是为了解决这些问题而生的。它可以包含多种类型的标识:

2.2 Java的严格验证机制

Java安全模型对证书验证特别严格,尤其是JDK 1.8及更高版本。当Java程序建立HTTPS连接时,会执行以下验证步骤:

  1. 检查证书是否过期
  2. 验证证书链是否可信
  3. 核对当前访问的主机名是否匹配证书中的标识
    • 先检查SANs字段
    • 如果没有SANs,才回退到CN字段
    • 如果两者都不匹配,就抛出我们看到的错误

这种机制导致很多历史遗留证书在现代Java环境下无法正常工作。我见过不少团队在升级JDK版本后突然出现这个错误,就是因为老证书没有配置SANs扩展。

3. 测试环境下的解决方案

对于开发和测试环境,我们可以用OpenSSL快速生成包含SANs的自签名证书。下面是我在实际工作中总结的最佳实践:

3.1 准备SANs配置文件

首先创建一个san.cnf文件,内容如下:

[req]
req_extensions = v3_req
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = *.example.com
IP.1 = 192.168.1.100

这个配置文件定义了:

3.2 分步生成证书

# 生成私钥
openssl genpkey -algorithm RSA -out server.key
# 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com" \
  -reqexts v3_req -config san.cnf
# 生成自签名证书
openssl x509 -req -days 365 -in server.csr \
  -signkey server.key -out server.crt \
  -extfile san.cnf -extensions v3_req

关键参数说明:

3.3 快速验证证书

生成证书后,可以用这个命令检查SANs是否设置成功:

openssl x509 -in server.crt -text -noout | grep -A 1 "Subject Alternative Name"

正确输出应该显示你在配置文件中定义的所有SANs条目。

4. 生产环境处理方案

生产环境的证书管理要谨慎得多,这里分享几种常见场景的解决方案:

4.1 联系证书颁发机构(CA)

正规CA颁发的证书通常都包含SANs扩展。如果遇到这个问题:

  1. 检查现有证书是否包含正确的SANs:
    openssl x509 -in production.crt -text -noout | grep -A 1 "Subject Alternative Name"
  2. 如果没有或不全,联系CA重新签发证书
  3. 提供需要添加的所有域名和IP地址

大多数商业CA都提供免费重新签发服务。去年我们为一个电商平台迁移到新域名时,就通过DigiCert在2小时内获得了更新后的多域名证书。

4.2 代码级解决方案(最后手段)

如果暂时无法更新证书,可以修改Java代码绕过验证(仅限紧急情况):

TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

重要警告:这种方法会完全禁用SSL验证,存在严重安全风险。只应在测试或内部可信网络中使用,生产环境强烈建议使用正规证书。

5. 常见问题排查技巧

在实际运维中,我总结了一些排查这类问题的实用技巧:

5.1 证书链完整性检查

有时候问题不在终端证书,而在中间证书。用这个命令检查完整链:

openssl verify -CAfile ca-bundle.crt your-certificate.crt

如果显示"OK"表示链完整,否则需要补充缺失的中间证书。

5.2 不同Java版本的差异

注意JDK版本间的行为差异:

可以用以下代码检查当前JVM使用的安全策略:

System.out.println("Security providers:");
for (Provider p : Security.getProviders()) {
    System.out.println(p.getName());
}

5.3 浏览器与Java的不同表现

经常有开发者困惑:"为什么浏览器访问正常,Java程序就报错?"这是因为:

这种差异正是SSL/TLS实现碎片化的典型表现。

到此这篇关于Java SSL证书错误:No subject alternative names present的解决方案的文章就介绍到这了,更多相关Java SSL证书错误内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文