忽略Java中的自签名证书

我在职业生涯中遇到过几次问题,就是我们有时希望允许自签名证书用于开发或测试目的。 Google的快速搜索显示了多年来无数Java开发人员遇到的麻烦。

根据确切的证书问题,您可能会收到类似以下内容之一的错误,尽管我几乎肯定有其他表现形式:

java.security.cert.CertificateException: Untrusted Server Certificate Chain

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

要解决此问题,通常需要修改JDK信任库文件,这可能会很痛苦,而且常常会遇到麻烦。 最重要的是,您团队中的每个开发人员都必须做同样的事情,并且您在每个新环境中都会遇到相同的问题。

幸运的是,有一种方法可以以通用的方式解决问题,而不会给开发人员带来任何负担。 我们将重点介绍普通的HttpURLConnection类型的连接,因为它是最通用的类​​型,仍应帮助您了解其他库的使用方向。 如果您使用的是Apache HttpClient,请参见此处

警告:知道您在做什么!

请注意使用此代码的含义:这意味着您完全不关心主机验证,而仅使用SSL来加密通信。 您不是要防止中间人攻击,也不是要确保您已连接到您认为是的主机。 通常可以归结为一些有效的情况:

  1. 您在锁定的LAN环境中操作。 您不容易受到攻击者拦截的请求(或者如果存在,则问题更大)。
  2. 您所处的测试或开发环境中,确保通信安全并不重要。

如果这符合您的需求,请继续进行。 否则,也许要三思而后行地想要完成什么。

解决方案:修改信任管理器

既然我们已经放弃了这个免责声明,我们就可以解决眼前的实际问题。 Java允许我们控制负责验证HttpsURLConnection的主机和证书的对象。 这可以在全球范围内完成,但是我敢肯定,有经验的人会畏缩于做出如此彻底的改变的想法。 幸运的是,我们还可以根据每个请求进行操作,并且由于很难在网络上找到此类示例,因此我在下面提供了代码。 这种方法很好,因为您无需在全球范围内换掉SSLSocketFactory实现。

随时获取它并在您的项目中使用它。

package com.mycompany.http;

import java.net.*;
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;

public class TrustModifier {
   private static final TrustingHostnameVerifier
      TRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();
   private static SSLSocketFactory factory;

   /** Call this with any HttpURLConnection, and it will
    modify the trust settings if it is an HTTPS connection. */
   public static void relaxHostChecking(HttpURLConnection conn)
       throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

      if (conn instanceof HttpsURLConnection) {
         HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
         SSLSocketFactory factory = prepFactory(httpsConnection);
         httpsConnection.setSSLSocketFactory(factory);
         httpsConnection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);
      }
   }

   static synchronized SSLSocketFactory
            prepFactory(HttpsURLConnection httpsConnection)
            throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

      if (factory == null) {
         SSLContext ctx = SSLContext.getInstance("TLS");
         ctx.init(null, new TrustManager[]{ new AlwaysTrustManager() }, null);
         factory = ctx.getSocketFactory();
      }
      return factory;
   }

   private static final class TrustingHostnameVerifier implements HostnameVerifier {
      public boolean verify(String hostname, SSLSession session) {
         return true;
      }
   }

   private static class AlwaysTrustManager implements X509TrustManager {
      public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public X509Certificate[] getAcceptedIssuers() { return null; }
   }

}

用法

要使用上面的代码,只需在打开流之前调用RelaxHostChecking()方法即可:

URL someUrl = ... // may be HTTPS or HTTP
HttpURLConnection connection = (HttpURLConnection) someUrl.openConnection();
TrustModifier.relaxHostChecking(connection); // here's where the magic happens

// Now do your work!
// This connection will now live happily with expired or self-signed certificates
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
...

在那里,它是支持自签名证书的本地化方法的完整示例。 这不会影响您的应用程序的其余部分,而其余部分将继续具有严格的托管检查语义。 该示例可以扩展为使用配置设置来确定是否应使用宽松的主机检查,如果使用此代码主要是通过自签名证书进行开发的一种方式,我建议您这样做。

参考: Carfey Software Blog上的 JCG合作伙伴 忽略了Java中的自签名证书

相关文章 :

翻译自: https://www.javacodegeeks.com/2011/12/ignoring-self-signed-certificates-in.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值