我现在正在尝试使用KeyManager和TrustManager的SSL配置,除了HostNameVerifier部分之外,一切似乎都很清楚。
我已经阅读了以下内容:
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/HostnameVerifier.html
https://lightbend.github.io/ssl-config/HostnameVerification.html
因此,基本上,当请求的URL和证书中的URL不匹配时,它就会生效。
处理此问题的最佳做法是什么?
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
// some code
}
};
从安全性(就像中间人攻击(的角度来看,我认为它必须一直返回false。但在这种情况下,这整件事的目的是什么
然而,大多数时候在互联网上冲浪时,我会遇到返回原始"true"的解决方案(没有任何争论(。
所以我很困惑什么时候、为什么以及如何使用它。
你能详细说明一下吗?
从安全性(比如中间人攻击(的角度来看,我认为它必须始终返回false。
几乎正确。只有当默认验证检测到问题时,才会调用此方法。在几乎所有情况下,这样的问题都意味着应该中止连接以确保其安全。
然而,大多数时候在互联网上冲浪时,我会遇到返回原始"true"的解决方案(没有任何争论(。
这几乎每次都是错误的。这些代码的作者通常不理解其中的含义(正如你正确地说的那样,可能是MITM(,只是希望他们的代码以某种方式工作。是的,它会起作用,但它也会在不应该起作用的时候起作用,即它不安全。
默认验证失败的典型原因是服务器使用错误的证书配置不当,或者使用错误的主机名(即不是证书中的主机名(访问服务器。
所以我很困惑何时、为什么以及如何使用它。
只有当您知道主机返回的证书主题错误,但您也知道具体会出什么问题,并将在实现中正确验证这一期望时,才应该使用它。
当然,最好不要在所有访问服务器的应用程序中都绕过,而是解决真正的问题。根据问题的实际原因,这通常意味着要么修复服务器上的证书,要么修复用于访问服务器的主机名。
检查会话主机是否符合我们的期望。
public boolean verify(String hostname, SSLSession session) {
return hostname.equals(session.getPeerHost());
}
如果您只是想让系统信任一个特定的证书来代替预期的主机名,您可以尝试以下(Kotlin(代码:
return if (hostname == "proxy.example.com") { // the host that is being connected to over TCP
val cert = session.peerCertificates[0] as? X509Certificate ?: return false
cert.subjectAlternativeNames.contains(listOf(2, "subject.example.com")) // the certificate that is being served
} else {
false
}
它不适用于一些只使用CN标识(而不是SAN(的旧证书,但修复起来很简单。