当前位置:  开发笔记 > 编程语言 > 正文

在Java客户端中接受服务器的自签名ssl证书

如何解决《在Java客户端中接受服务器的自签名ssl证书》经验,为你挑选了3个好方法。

它看起来像一个标准问题,但我无法在任何地方找到明确的方向.

我有java代码尝试连接到可能具有自签名(或过期)证书的服务器.代码报告以下错误:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

据我了解,我必须使用keytool并告诉java允许这种连接是可以的.

解决此问题的所有说明都假设我完全熟练使用keytool,例如

为服务器生成私钥并将其导入密钥库

有没有人可以发布详细说明?

我正在运行unix,所以bash脚本最好.

不确定它是否重要,但代码是在jboss中执行的.



1> Pascal Thive..:

这里基本上有两个选项:将自签名证书添加到JVM信任库或将客户端配置为

选项1

从浏览器导出证书并将其导入JVM信任库(以建立信任链):

\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

选项2

禁用证书验证:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

请注意,我根本不推荐选项#2.禁用信任管理器会使SSL的某些部分失效,并使您在中间攻击中容易受到攻击.首选选项#1,或者更好的是,让服务器使用由知名CA签名的"真实"证书.


@EJP通过教导人们教育他们,而不是隐藏东西.所以保守秘密或默默无闻都不是解决方案.这段代码是公开的,Java API是公开的,讨论它比忽略它更好.但我可以与你同住,不同意.
@EJP我真的不推荐第二个选项(我已经更新了我的答案,以明确).但是,不发布它不会解决任何问题(这是公共信息),并且不会恕我直言.
另一个选项 - 您未提及的选项 - 是通过自己修复服务器或通过调用相关支持人员来确认服务器的证书.单个主机证书真的很便宜; 与自签名的东西一起玩耍是吝啬的愚蠢(即,对于那些不熟悉英语成语的人来说,这是一套完全愚蠢的优先事项,需要花费很多才能几乎没有任何费用).
不仅仅是MIM攻击.它使您易于连接到错误的站点.这是完全不安全的.请参阅RFC 2246.我反对始终发布此TrustManager.它甚至不符合自己的规范.
@Rich,已经晚了6年,但是您也可以通过点击锁定图标 - >更多信息 - >查看证书 - >详细信息选项卡 - >导出...来获取Firefox中的服务器证书.它隐藏得很好.

2> K.Nicholas..:

我将此问题追溯到不属于默认JVM可信主机的证书提供程序JDK 8u74.提供商是www.identrust.com,但这不是我试图连接的域名.该域名已从该提供商处获得其证书.请参阅JDK/JRE中默认列表的交叉根覆盖信任? - 读下几个条目.另请参阅哪些浏览器和操作系统支持Let's Encrypt.

因此,为了连接到我感兴趣的域,其中有identrust.com我发出的证书,我执行了以下步骤.基本上,我必须得到jVM DST Root CA X3信任的identrust.com()证书.我能够使用Apache HttpComponents 4.5这样做:

1:在证书链下载说明中获取不受信任的证书.单击DST根CA X3链接.

2:将字符串保存到名为"DST Root CA X3.pem"的文件中.务必在文件的开头和结尾添加"----- BEGIN CERTIFICATE -----"和"----- END CERTIFICATE -----"行.

3:使用以下命令创建一个java密钥库文件cacerts.jks:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4:将生成的cacerts.jks密钥库复制到java /(maven)应用程序的resources目录中.

5:使用以下代码加载此文件并将其附加到Apache 4.5 HttpClient.这将解决所有具有从indetrust.comutil oracle 发布的证书的域的问题,该证书将证书包含在JRE默认密钥库中.

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

当项目构建时,cacerts.jks将被复制到类路径中并从那里加载.在这个时间点,我没有测试其他ssl网站,但如果上面的代码"链"在这个证书中,那么它们也会起作用,但是我不知道.

参考:自定义SSL上下文以及如何使用Java HttpsURLConnection接受自签名证书?


仔细阅读问题(和答案).

3> 小智..:

Apache HttpClient 4.5支持接受自签名证书:

SSLContext sslContext = SSLContexts.custom()
    .loadTrustMaterial(new TrustSelfSignedStrategy())
    .build();
SSLConnectionSocketFactory socketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry reg =
    RegistryBuilder.create()
    .register("https", socketFactory)
    .build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);        
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

这将构建一个SSL套接字工厂,它将使用TrustSelfSignedStrategy它,将其注册到自定义连接管理器,然后使用该连接管理器执行HTTP GET.

我同意那些吟唱"不要在生产中这样做"的人,但是有一些用例可以接受生产之外的自签证书; 我们在自动化集成测试中使用它们,这样即使不在生产硬件上运行,我们也会使用SSL(就像在生产中一样).

推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有