跳过HTTPS调用时证书SLL问题

今天在对接一个银商的项目接口,测试环境调用,在写调用util的时候,有一些证书相关问题。

对于http换成支持https调用,网上有很多类的重写方法。就不细说了。

先把代码贴一下:

(还有2个类,我稍微改下晚点补上代码~)

SSLClientUtil.java

package com.naka.fizzbuzz;
import java.net.Socket;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.*;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
public class SSLTrustClient extends SSLClient {
  public SSLTrustClient() {
  } 
  
  @Override
  public void prepareCertificate() throws Exception { 
      // 跳过证书验证
      KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

      SSLContext ctx = SSLContext.getInstance("TLS");
      // 如果这里是,会报错:Algorithm constraints check failed on signature algorithm: MD5withRSA
      X509TrustManager tm = new X509ExtendedTrustManager() {
          @Override
          public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {

          }

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {

          }

          @Override
          public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {

          }

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {

          }

          @Override
          public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return null;
          }
    };
    // 设置成已信任的证书 
    ctx.init(null, new TrustManager[] { tm }, null); 
    this.connectionSocketFactory = new SSLConnectionSocketFactory(ctx, new HostnameVerifier(){
        @Override
        public boolean verify(String hostname, SSLSession session) {
            // 解决报错:javax.net.ssl.SSLPeerUnverifiedException: Certificate for  doesn't match any of the subject alternative names: []
            // 跳过域名验证
            return true;
        }
    });

  }

  
    /**
     * 因api需要TLSv1.1及以上版本,故新加一个方法实现
     */
    @Override
    public void prepareApiCertificate() throws Exception{
        // 跳过证书验证 
        SSLContext ctx = SSLContext.getInstance("TLSv1.1");
        X509TrustManager tm = new X509TrustManager(){

            @Override
            public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException{
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,String authType) throws CertificateException{
            }

            @Override
            public X509Certificate[] getAcceptedIssuers(){
                return null;
            }
        };
        // 设置成已信任的证书 
        ctx.init(null, new TrustManager[] { tm }, null);
        this.connectionSocketFactory = new SSLConnectionSocketFactory(ctx);
    }
}

说一下遇到的2个问题:

1.跳过域名校验:

本来的代码是这样写的:

// 设置成已信任的证书 
    ctx.init(null, new TrustManager[] { tm }, null); 
    this.connectionSocketFactory = new SSLConnectionSocketFactory(ctx);

报错:

javax.net.ssl.SSLPeerUnverifiedException: Certificate for  doesn't match any of the subject alternative names: []

因为我在调用的时候是用ip调用的,默认会去校验域名

因此重写HostnameVerifier,总是return true,跳过校验

 

 

2.跳过证书算法校验:

报错:

Caused by: java.security.cert.CertPathValidatorException: Algorithm constraints check failed on signature algorithm: MD5withRSA
 

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Certificates do not conform to algorithm constraints
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1964)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:328)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:322)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1614)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
	at com.naka.fizzbuzz.SSLClientUtil.doPost(SSLClientUtil.java:37)
	at com.naka.fizzbuzz.SSLClientUtil.doPost(SSLClientUtil.java:28)
	at com.naka.fizzbuzz.GiftcardTest.sendPostHttps(GiftcardTest.java:103)
	at com.naka.fizzbuzz.GiftcardTest.demo2(GiftcardTest.java:63)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.security.cert.CertificateException: Certificates do not conform to algorithm constraints
	at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1127)
	at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:1051)
	at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:993)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596)
	... 52 more
Caused by: java.security.cert.CertPathValidatorException: Algorithm constraints check failed on signature algorithm: MD5withRSA
	at sun.security.provider.certpath.AlgorithmChecker.check(AlgorithmChecker.java:278)
	at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:1123)
	... 55 more

这个报错,是校验证书不通过。而且这个是JDK1.8才会出现的问题,如果换回JDK1.7是不会报错的。

网上普遍的解决办法:

1. 在cmd窗口输入命令"where java"检查你实际使用的JDK到底在哪里(我用的是Windows7)

2. 重装那个JDK(这一步可能不需要)

3. 编辑文件java.security(C:\Program Files\Java\jdk1.8.0_191\jre\lib\security\java.security)

4. 去掉"jdk.certpath.disabledAlgorithms"里的"MD5",去掉"jdk.tls.disabledAlgorithms"里的"MD5withRSA"

5.打开环境变量设置,去掉path里的"C:\Program Files (x86)\Common Files\Oracle\Java\javapath;"

6.重启电脑

 

其实这个解决的就是JDK1.7和1.8配置文件的差别。

 

ok,本地环境这样改还可以,线上不能因为一个https调用改环境的jdk版本。

 

参考了一个博主的代码:https://blog.csdn.net/weixin_42330402/article/details/80510020 

 

如果TrustAnyTrustManager是实现接口X509TrustManager,而不是继承抽象类:X509ExtendedTrustManager,那么JDK则会默认用自己的实现类AbstractTrustManagerWrapper来对服务器的证书算法进行验证,检查她们是否符合java.security里的配置要求!而如果我们的TrustAnyTrustManager继承了抽象类:X509ExtendedTrustManager,则SSLContextImpl就会使用我们自己的TrustAnyTrustManager来验证证书算法,而我们这个类所有的验证方法都是空方法(也就是不验证),那么自然也就不会抛异常了。
 

本来的代码是这样写的:

X509TrustManager tm = new X509TrustManager() {

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {

          }

          @Override
          public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return null;
          }
    };

你可能感兴趣的:(java)