gpt4 book ai didi

java - 具有主机名验证的 SSLContext

转载 作者:太空宇宙 更新时间:2023-11-03 13:16:09 31 4
gpt4 key购买 nike

在测试我的客户端-服务器分布式系统时,一开始我很惊讶地发现 TLS 的默认 JSSE 实现不进行主机名验证。我在 this 中尝试了接受的答案问题,但我的用例有点不同。我使用 RabbitMQ 的连接工厂,它抽象了 SSLSocket 的构造。我只是为连接工厂提供 SSLContext。我确实找到了很多关于 HTTPS 甚至一些其他协议(protocol)的信息,但不是总能使用的通用协议(protocol),即使是自定义协议(protocol)也是如此。

不过,除了使用 X509ExtendedTrustManager 之外,关于创建域验证 SSLContext 的内容并不多。在调试时,我可以看到

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init((KeyStore) null);
tmf.getTrustManagers();

返回一个 TrustManager,一个 X509TrustManagerImpl,根据 this页面扩展 X509ExtendedTrustManager。但是,这不会拒绝有缺陷的证书(“有缺陷”是指证书与服务器的主机名不匹配)。

然后我开始编写自己的 X509ExtendedTrustManager,它从我的 TrustManagerFactory 委托(delegate)给信任管理器:

final TrustManager[] trustManagers = tmf.getTrustManagers();
X509ExtendedTrustManager x509ExtendedTrustManager = new X509ExtendedTrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
checkClientTrusted(x509Certificates, s);
}

@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
checkServerTrusted(x509Certificates, s);
}

@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
checkClientTrusted(x509Certificates, s);
}

@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
checkServerTrusted(x509Certificates, s);
}

public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
for (TrustManager trustManager : trustManagers)
((X509TrustManager)trustManager).checkClientTrusted(x509Certificates, s);
}

public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
for (TrustManager trustManager : trustManagers)
((X509TrustManager)trustManager).checkServerTrusted(x509Certificates, s);

for (X509Certificate x509Certificate : x509Certificates) {
Collection<List<?>> alternativeNameCollection = x509Certificate.getSubjectAlternativeNames();
if (alternativeNameCollection != null) {
for (List alternativeNames : alternativeNameCollection) {
if (alternativeNames.get(1).equals(host))
return;
}
}
}

throw new CertificateException("Certificate hostname and requested hostname don't match");
}

public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};

这终于奏效了。但我不敢相信不会有更清洁的方法来做到这一点。基本上我正在寻找的是标准的东西,因为我认为我正在做的也很标准。我阅读了有关 HostnameVerifier 的内容,但是有没有办法在不使用 HTTPS 的情况下将它与 SSLContext 一起使用?某处是否有 X509ExtendedTrustManager 的主机名验证实现?我确信我正在重新发明已经写好的东西。

编辑: this是一个很好的工作示例。不过仍然是自定义代码。

编辑 2:问题仍然存在于 RabbitMQ,因为 RabbitMQ 解析 DNS 并将 IP 地址传递给 validator ,这当然总是失败。所以 X509ExtendedTrustManager 似乎仍然是可行的方法。

最佳答案

主机名验证不是 SSL 的一部分。它是 HTTPS 的一部分。您正在调查错误的层和错误的 API。您应该查看 HttpURLConnectionHostnameVerifier

关于java - 具有主机名验证的 SSLContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36548757/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com