博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于weblogic host name varify 的一个问题记录
阅读量:6004 次
发布时间:2019-06-20

本文共 5097 字,大约阅读时间需要 16 分钟。

关于weblogic host name varify 的一个问题

问题是项目组一个同事发现的。
出问题的代码如下:

1
2
3
4
5
6
7
8
9
10
StringBuilder document = 
new 
StringBuilder();
URL url = 
new 
URL(Constants.URL);
// 远程url,实际值为:https://mapi.alipay.com/...
URLConnection conn = url.openConnection();
BufferedReader reader = 
new 
BufferedReader(
new 
InputStreamReader(
    
conn.getInputStream()));
String line = 
null
;
while 
((line = reader.readLine()) != 
null
) {
  
document.append(line + 
" "
);
}
reader.close();

当在weblogic服务器上运行时,抛出了如下异常:

1
2
3
4
5
6
7
8
9
<
2013
-
10
-
22 
下午
02
11
12
秒 CST> <Error> <HTTP> <BEA-
101019
> <[ServletContext
@25331129
[app:httpTest module:WebContent path:/TestHTTPS spec-version:
2.5
]] Servlet failed with IOException
javax.net.ssl.SSLKeyException: [Security:
090504
]Certificate chain received from mapi.alipay.com - 
110.75
.
142.31 
failed hostname verification check. Certificate contained *.alipay.com but check expected mapi.alipay.com
  
at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireException(Unknown Source)
  
at com.certicom.tls.interfaceimpl.TLSConnectionImpl.fireAlertSent(Unknown Source)
  
at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
  
at com.certicom.tls.record.handshake.HandshakeHandler.fireAlert(Unknown Source)
  
at com.certicom.tls.record.handshake.ClientStateReceivedServerHello.handle(Unknown Source)
  
Truncated. see log file 
for 
complete stacktrace
>

经过那位同事的不懈努力,发现了问题所在:
在作为客户端发起https请求时,weblogic服务器会对所请求的服务端做SSL的主机名验证,验证方法是对服务端的授权证书和https请求的URL进行比对,比对规则视配置项而定。这项配置在weblogic服务器的console→环境→服务器→配置→SSL页面上,展开“高级”(advanced)菜单中。查看其中的“主机名验证”(host name varify )选项,会发现这里的默认配置为“BEA 主机名验证器”(BEA host name varify )。这个默认配置会对授权证书和URL进行完全匹配的验证,也就是必须完全相同,才认为是验证通过,并给https请求放行。
对应到系统中出问题的地方,就是因为授权证书中的地址是“*.alipay.com”(采用了通配符的写法),而实际访问的地址是“mapi.alipay.com”。在完全匹配的规则下,当然会验证失败。
网上查到的解决办法,多半是直接关闭weblogic的主机名验证服务,也就是在上述配置项中选择“无”(none)。但是这种选择确实有风险。
经过那位同事的继续努力,发现了另一种解决方法
将代码修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
StringBuffer result = 
new 
StringBuffer();
HttpClient httpClient = 
new 
DefaultHttpClient();
// 使用的请求方式是GET
HttpGet httpGet = 
new 
HttpGet(Constants.URL);
try 
{
  
HttpResponse response = httpClient.execute(httpGet);
  
HttpEntity httpEntity = response.getEntity();
  
if 
(httpEntity != 
null
) {
    
InputStream inputStream = httpEntity.getContent();
    
byte
[] responseByte = 
new 
byte
[
2048
];
    
int 
len = 
0
;
    
while 
((len = inputStream.read(responseByte)) != -
1
) {
      
result.append(
new 
String(responseByte, 
0
, len));
    
}
  
}
catch 
(ClientProtocolException e) {
  
e.printStackTrace();
catch 
(IOException e) {
  
e.printStackTrace();
finally 
{
  
// 关闭http请求
  
httpClient.getConnectionManager().shutdown();
}

最主要的修改点,就是将直接用URL打开URLConnection的方法用HttpClient进行了改写。改写之后,即使weblogic服务器的配置仍然是“BEA 主机名验证器”,https请求也能够畅通无阻。

之所以能够成功,是因为HttpClient中,对发起的Https请求会附加一个主机名验证器,默认的是BrowserCompatHostnameVerifier。这个验证器与Firefox的工作方式是相同的,它可以匹配所有子域的通配符(比如”*.foo.com”)。HttpClient还有两个主机名验证器,按下不表。
然后,那位同事和我们讨论了一下为什么使用了HttpClient之后,weblogic上配置的主机名验证器就失效了呢?
weblogic在对外发出https请求时,会将这个请求封装为一个“weblogic.security.SSL.SSLClientInfo”类的实例。在这个实例中,有一个字段是“private HostnameVerifier hostnameVerifier;”。weblogic在通过“weblogic.security.utils.SSLSetup"类来构建这个实例的时候,会判断原有连接中是否自带有HostnameVerifier。如果有,则使用原配;否则,就会按照weblogic服务器的配置,组装上一个主机名验证器。
所以,当使用了HttpClient之后,服务器就会按照HttpClient自带的主机名验证器进行验证,而自己的配置却被置之脑后了。
除了使用HttpClient,还有两种方式可以解决这个问题。
其一是仿照HttpClient的思路,为Https请求带上一个自定义的主机名验证器,
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
URL url = 
new 
URL(Constants.URL);
// 远程url
HttpsURLConnection conn = 
new 
HttpsURLConnection(url);
conn.setHostnameVerifier(
new 
HostnameVerifier() {
  
@Override
  
public 
boolean 
verify(String arg0, SSLSession arg1) {
    
System.out.println(
"这里是自定义的特殊处理:只打印,不校验"
);
    
return 
true
;
  
}
});
System.out.println(conn.getHostnameVerifier());
BufferedReader reader = 
new 
BufferedReader(
new 
InputStreamReader(
    
conn.getInputStream()));
String line = 
null
;
while 
((line = reader.readLine()) != 
null
) {
  
document.append(line + 
" "
);
}
reader.close();

这里使用的是HttpsURLConnection,因为只有这个类,才有setHostnameVerifier等相关接口。

另一种方式是为weblogic自定义一个主机名校验器,并为服务器做“定制主机名验证器”的相关配置。
自定义校验器的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package 
verifier;
import 
javax.net.ssl.SSLSession;
import 
weblogic.security.SSL.HostnameVerifier;
/**
 
* 自定义的主机名验证类
 
* @since 2013-10-14
 
* @version 1.0.0
 
*/
public 
class 
CustomerVerifier 
implements 
HostnameVerifier {
  
/**
   
* 验证方法。
   
* @since 2013-10-14
   
* @param arg0
   
* @param arg1
   
* @return
   
* @see weblogic.security.SSL.HostnameVerifier#verify(java.lang.String,
   
*   javax.net.ssl.SSLSession)
   
*
   
*/
  
@Override
  
public 
boolean 
verify(String arg0, SSLSession arg1) {
    
System.out.println(
"this is the CustomerVerifier by Loy, arg0 = "
        
+ arg0 + 
", arg1 = " 
+ arg1);
    
return 
true
;
  
}
}

在服务器上做如下配置:

1、主机名验证选项选择“定制主机名验证器”;
2、“定制主机名验证器:”输入框中输入自定义的类的全路径类名,如“verifier.CustomerVerifier”;
3、将自定义类的class文件放到weblogic服务器的ClassPath下,如将其导出为jar包,并在weblogic启动脚本中加入配置:set CLASSPATH=%CLASSPATH%;D:\bea\user_projects\domains\car_domain_10\lib\CustomerVerifier.jar
配置完成后,重启服务器,然后再次运行最早的那段会抛出异常的代码。正常情况下,这个请求就能够获得返回数据了。

本文转自 斯然在天边 51CTO博客,原文链接:http://blog.51cto.com/winters1224/1313111,如需转载请自行联系原作者

你可能感兴趣的文章
那些SCOM 管理包开发中遇到的坑1–Powershell scriptBlock Invoke执行结果的类型
查看>>
关于Server Sql 2008触发器的使用
查看>>
mac常见命令
查看>>
Redhat 系统相关调优参数注解
查看>>
nextus的使用
查看>>
Python自动化开发学习5-2-subprocess模块
查看>>
编程实现最小化窗口到桌面右下角图标的代码
查看>>
ELK stack实战之结合rsyslog分析系统日志(auth.log)
查看>>
网络管理工具与IT运维管理平台的差别
查看>>
五一期间安全回顾 木马威胁提升 移动设备数据泄漏受重视
查看>>
VDI序曲二十 桌面虚拟化和RemoteApp集成到SharePoint 2010里
查看>>
压缩介绍、bz2、gz、xz压缩工具
查看>>
StretchRect...果然和文档上说的一样
查看>>
Python成生随机KEY工具
查看>>
将一个数组拆分为几个至少三个元素的递增子序列
查看>>
备忘,解决WIN10下COM注册问题
查看>>
cx_Oracle install
查看>>
jquery ajax从后台获取数据
查看>>
基于Windows平台TSM 6.x版本下,如何删除初始化失败的实例。
查看>>
Start Code School Today!
查看>>