java - HttpsURLConnections 默认主机名验证程序
问题描述
我正在使用一个HttpURLConnection
来创建一个 POST 请求(用于在某个 OAuth2 令牌端点获取令牌)。令牌端点使用 HTTPS。我想知道关于 HTTPS 的主机名验证是如何工作的。的默认主机名验证器HttpsURLConnection
似乎如下 [1]:
/**
* HostnameVerifier provides a callback mechanism so that
* implementers of this interface can supply a policy for
* handling the case where the host to connect to and
* the server name from the certificate mismatch.
*
* The default implementation will deny such connections.
*/
private static HostnameVerifier defaultHostnameVerifier =
new HostnameVerifier() {
public boolean verify(String urlHostname, String certHostname) {
return false;
}
};
我预计我的 POST 请求会失败,因为此验证程序总是返回false
。不是这种情况。该评论已经指出存在某种回调机制。我不知道的是:defaultHostnameVerifier
验证连接的主机名和证书还是虚拟实现?
我当前的编码如下所示:
private HttpURLConnection openConnection(String url) throws IOException {
URL urly = new URL(url);
final HttpURLConnection con;
Proxy proxy = getProxy();
if (proxy == null) {
con = (HttpURLConnection) urly.openConnection();
} else {
con = (HttpURLConnection) urly.openConnection(proxy);
}
if (con instanceof HttpsURLConnection) {
HostnameVerifier verifier = ((HttpsURLConnection) con).getHostnameVerifier(); // there is a default set
System.out.println(verifier.getClass().getName());
}
return con;
}
AsyncHttpClient
关于[2] ,我找到了一些解释。由于我此时不使用它,因此我可以安全地使用默认实现吗?
解决方案
正如顶部的评论所说,该类不再使用;它是抽象的用户可见类,现在被javax.net.HttpsURLConnection取代,您将观察到它具有相同的代码。但是 https URL 的实现类是sun.net.www.protocol.https.HttpsURLConnectionImpl,它只是包装(委托给)sun.net.www.protocol.https.DelegateHttpsURLConnection ,它是sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection的子类建立实际连接使用sun.net.www.protocol.HttpsClient ,特别是 .afterConnect()。作为背景,在 Java 的早期版本中SSLSocket
没有做hostname校验,所以HttpsURLConnection的实现只好加了。在 Java 7 中,SSLSocket
确实支持“端点识别”,因此当 afterConnect() 识别到此 URL 连接上的 hostnameVerifier 是默认值时,它会关闭needToCheckSpoofing
并设置SSLSocket
to do 端点识别。
javax.net.ssl.SSLSocket是一个抽象类,实际上是由sun.security.ssl.SSLSocketImpl和几十个相关类实现的,包括sun.security.ssl.ClientHandshaker.serverCertificate()调用可配置的信任管理器,默认情况下是sun.security.ssl.X509TrustManagerImpl在checkTrusted()中调用了checkIdentity(),它调用了带有 TYPE_TLS 的sun.security.util.HostnameChecker (实际上是 HTTPS RFC 2818),并进行了实际检查。
很高兴你问?
PS:对该网页的分析,即 HttpsURLConnection.DefaultHostnameVerifier 仅因不匹配而被调用,是完全错误的。如上所述,它被绕过并且从未被实际实现调用。
此外,我假设您意识到 java 7 多年来一直不受支持,除非您付费。虽然我知道在最近的版本中这个区域没有改变。Java 11 确实添加了一个新的 java.net.http.HttpClient,它在功能上取代了 [Http,Https]URLConnection。
推荐阅读
- python - 是否有基于相对距离生成坐标的方法或方程?(生成树)
- r - Time_trans 仅在 R 中与 posixct 类的对象一起使用
- python - 集线器连接未在 Python 中使用 SignalR 调用服务器方法
- c - if (strcmp(file_name, "stdout") == 0)?
- javascript - 尝试验证 sessionStorage 令牌并替换路径 - 在 reactjs 中不起作用
- java - 在 JavaFX 中,如何将字段声明为私有?
- django - 在 Django/Djongo 的另一个抽象模型中是否可以有一个抽象模型?
- sql - 从字符串中删除日期,转换为日期并检查是否等于今天的日期
- deep-learning - 有没有一种方便的方法可以只将 Pytorch 中的模型架构信息保存到 protobuf 规则文件中?
- terraform - 在通过 Terraform 部署初始 SQS 队列后添加 DLQ?