Java SSL/TLS证书认证逻辑

news2024/10/7 6:32:14

前言

最近做项目使用httpclient转发https请求,但是遇到一些坑,尤其是证书的认证,证书认证一般都是单向的,除非相互访问,证书一般基于host,但是如果访问需要ip,那么JDK默认的认证就会不通过,但是SSL的握手只要jdk信任证书就可以通过认证。

demo

还是上2章的zuul 的demo,Apache httpclient 4.5.13

## 配置zuul的路由规则
zuul:
  routes:
    rule1:
      path: /demo/**
      url: https://202.89.233.101:443/

url配置IP,实际上应该配置host,但是host需要DNS的解析,并不是所有情况DNS都能解析的。 

IP证书认证不过 

这里使用cn.bing.com的IP来实验,通过ping获取ip,SSL默认的端口为443,访问http://localhost:8080/demo/ 

Caused by: javax.net.ssl.SSLPeerUnverifiedException: Certificate for <202.89.233.101> doesn't match any of the subject alternative names: [*.platform.bing.com, *.bing.com, bing.com, ieonline.microsoft.com, *.windowssearch.com, cn.ieonline.microsoft.com, *.origin.bing.com, *.mm.bing.net, *.api.bing.com, *.cn.bing.net, *.cn.bing.com, ssl-api.bing.com, ssl-api.bing.net, *.api.bing.net, *.bingapis.com, bingsandbox.com, feedback.microsoft.com, insertmedia.bing.office.net, r.bat.bing.com, *.r.bat.bing.com, *.dict.bing.com, *.ssl.bing.com, *.appex.bing.com, *.platform.cn.bing.com, wp.m.bing.com, *.m.bing.com, global.bing.com, windowssearch.com, search.msn.com, *.bingsandbox.com, *.api.tiles.ditu.live.com, *.ditu.live.com, *.t0.tiles.ditu.live.com, *.t1.tiles.ditu.live.com, *.t2.tiles.ditu.live.com, *.t3.tiles.ditu.live.com, *.tiles.ditu.live.com, 3d.live.com, api.search.live.com, beta.search.live.com, cnweb.search.live.com, dev.live.com, ditu.live.com, farecast.live.com, image.live.com, images.live.com, local.live.com.au, localsearch.live.com, ls4d.search.live.com, mail.live.com, mapindia.live.com, local.live.com, maps.live.com, maps.live.com.au, mindia.live.com, news.live.com, origin.cnweb.search.live.com, preview.local.live.com, search.live.com, test.maps.live.com, video.live.com, videos.live.com, virtualearth.live.com, wap.live.com, webmaster.live.com, www.local.live.com.au, www.maps.live.com.au, webmasters.live.com, ecn.dev.virtualearth.net, www.bing.com]
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:507)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:437)
	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:376)
	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.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118)
	at org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter.forwardRequest(SimpleHostRoutingFilter.java:392)
	at org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter.forward(SimpleHostRoutingFilter.java:311)
	at org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter.run(SimpleHostRoutingFilter.java:227)

报错了,因为证书是host,使用IP访问的时候host是认证不了的

那么关键是org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:507)

看这个类的定义,详细的说明了,证书认证不过怎么处理,导入自签证书或者jdk没收录的证书即可实现认证

 看定义SSLv2,要制定协议版本TLS1.2 TLS1.3(extend),支持的加密套件,比如国密就不支持,需要额外的jar。

 那么zuul的证书验证报错原理是默认情况下:org.apache.http.conn.ssl.DefaultHostnameVerifier

    public boolean verify(final String host, final SSLSession session) {
        try {
            final Certificate[] certs = session.getPeerCertificates();
            final X509Certificate x509 = (X509Certificate) certs[0];
            verify(host, x509);
            return true;
        } catch (final SSLException ex) {
            if (log.isDebugEnabled()) {
                log.debug(ex.getMessage(), ex);
            }
            return false;
        }
    }

读取host(zuul的配置转发的url读取,这里配置了IP),获取证书链,获取链尾部的证书(尾部即第一个证书,根证书是CA的认证逻辑) ,判断证书的host是否相同,实际上也可以用IP作为证书的host

    public void verify(
            final String host, final X509Certificate cert) throws SSLException {
        final HostNameType hostType = determineHostFormat(host);
        final List<SubjectName> subjectAlts = getSubjectAltNames(cert);
        if (subjectAlts != null && !subjectAlts.isEmpty()) {
            switch (hostType) {
                case IPv4:
                    matchIPAddress(host, subjectAlts);
                    break;
                case IPv6:
                    matchIPv6Address(host, subjectAlts);
                    break;
                default:
                    matchDNSName(host, subjectAlts, this.publicSuffixMatcher);
            }
        } else {
            // CN matching has been deprecated by rfc2818 and can be used
            // as fallback only when no subjectAlts are available
            final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
            final String cn = extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
            if (cn == null) {
                throw new SSLException("Certificate subject for <" + host + "> doesn't contain " +
                        "a common name and does not have alternative names");
            }
            matchCN(host, cn, this.publicSuffixMatcher);
        }
    }

获取host的过程,以上面的bing证书为例,JDK读取后会区分是DNS(type=2)还是IP(type=7)

   static List<SubjectName> getSubjectAltNames(final X509Certificate cert) {
        try {
            final Collection<List<?>> entries = cert.getSubjectAlternativeNames();
            if (entries == null) {
                return Collections.emptyList();
            }
            final List<SubjectName> result = new ArrayList<SubjectName>();
            for (final List<?> entry : entries) {
                final Integer type = entry.size() >= 2 ? (Integer) entry.get(0) : null;
                if (type != null) {
                    if (type == SubjectName.DNS || type == SubjectName.IP) {
                        final Object o = entry.get(1);
                        if (o instanceof String) {
                            result.add(new SubjectName((String) o, type));
                        } else if (o instanceof byte[]) {
                            // TODO ASN.1 DER encoded form
                        }
                    }
                }
            }
            return result;
        } catch (final CertificateParsingException ignore) {
            return Collections.emptyList();
        }
    }

笔者怀疑是jdk的问题,毕竟jdk的证书与操作系统不通用,但是go语言也是同样的逻辑,也是解析为IP和host,然后验证。

可以看到先把host判断类型,IPv4、IPv6、DNS(默认) ,比如bing的证书,这定义了很多DNS

导出证书方式,以Chrome 浏览器访问bing为例

先点击锁🔐图标,然后点击连接是安全的,也可能不安全,也是点击这一行

导出,选择Base64格式,其他的格式也可以,实际上JDK也可以支持,选择每一层证书可以看证书的信息

证书链,是从根证书开始的过程,如果是自签证书一般自己就是根证书,根证书一般是CA颁发用来签名的。

比如bing的根证书,操作系统就有认证

 

比如bing就是www.digicert.com 颁发的根证书,认证的,根证书有公钥和hash签名,根证书的私钥只有证书机构自己有,根证书是操作系统或浏览器信任的,所以根证书颁发的签名证书是信任的。证书认证的过程就是把自己的证书加入根证书的链中。

证书签名是使用私钥加密hash签名,使用SSL加密传输,对方使用公钥解密,然后使用自己的hash签名和解密的hash比对,相同表示没有篡改,否则都是已经篡改。

解决IP认证证书是host的情况

那么怎么解决呢,

  1. 使用host转发,host转发不涉及证书验证host的问题
  2. 使用IP的证书,不推荐,IP很可能经常变化,域名是相对长期固定的,证书也是长期的
  3. 使用证书host配置验证,zuul以这个为例

以zuul为例,实际上就是host的传递问题,验证证书时,zuul通过url解析,配置host域名转发即可,如果一定要配置IP,那么在org.springframework.cloud.netflix.zuul.filters.ZuulProperties

ZuulRoute

中增加dns的字段,配置各个url正确的host后,然后通过threadlocal传递到转发逻辑,这样写的比较死,实际上可以在创建连接的工厂里,通过开关忽略host校验

public class ZuulApacheHttpClientConnectionManagerFactory
        implements ApacheHttpClientConnectionManagerFactory {

    private static final Log LOG = LogFactory
            .getLog(ZuulApacheHttpClientConnectionManagerFactory.class);
    
    private boolean ignoreHostVerify;

    public boolean isIgnoreHostVerify() {
        return ignoreHostVerify;
    }

    public void setIgnoreHostVerify(boolean ignoreHostVerify) {
        this.ignoreHostVerify = ignoreHostVerify;
    }

    public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
                                                            int maxTotalConnections, int maxConnectionsPerRoute) {
        return newConnectionManager(disableSslValidation, maxTotalConnections,
                maxConnectionsPerRoute, -1, TimeUnit.MILLISECONDS, null);
    }

    @Override
    public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
                                                            int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
                                                            TimeUnit timeUnit, RegistryBuilder registryBuilder) {
        if (registryBuilder == null) {
            registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register(HTTP_SCHEME, PlainConnectionSocketFactory.INSTANCE);
        }
        if (disableSslValidation) {
            try {
                final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null,
                        new TrustManager[] { new DisabledValidationTrustManager() },
                        new SecureRandom());
                registryBuilder.register(HTTPS_SCHEME, new SSLConnectionSocketFactory(
                        sslContext, NoopHostnameVerifier.INSTANCE));
            }
            catch (NoSuchAlgorithmException e) {
                LOG.warn("Error creating SSLContext", e);
            }
            catch (KeyManagementException e) {
                LOG.warn("Error creating SSLContext", e);
            }
        }
        else {
            if (ignoreHostVerify) {
                try {
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(null, null, new SecureRandom());
                    registryBuilder.register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE));
                } catch (KeyManagementException | NoSuchAlgorithmException e) {
                    throw new RuntimeException(e);
                }
            } else {
                registryBuilder.register("https",
                        SSLConnectionSocketFactory.getSocketFactory());
            }
        }
        final Registry<ConnectionSocketFactory> registry = registryBuilder.build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
                registry, null, null, null, timeToLive, timeUnit);
        connectionManager.setMaxTotal(maxTotalConnections);
        connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

        return connectionManager;
    }

    class DisabledValidationTrustManager implements X509TrustManager {

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

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

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

    }

}

加上配置

@Configuration
public class DemoConfiguration {
    
    @Bean
    @ConditionalOnProperty(name = "zuul.ssl.ignore.host", havingValue = "true", matchIfMissing = false)
    public ApacheHttpClientConnectionManagerFactory initApacheHttpClientConnectionManagerFactory(){
        ZuulApacheHttpClientConnectionManagerFactory clientConnectionManagerFactory = new ZuulApacheHttpClientConnectionManagerFactory();
        clientConnectionManagerFactory.setIgnoreHostVerify(true);
        return clientConnectionManagerFactory;
    }
}

 加上开关后

笔者尝试后结果如下(修改了端口,笔者开了几个demo):

说明访问成功,只是浏览器限制了我们访问 

自建证书试验

那么根证书是没有认证的呢,或者没有根证书,就是我们自己通过openssl或者jdk的工具做的呢,先做一个证书试试,macOS内置了openssl,实际上很多Linux也内置了,不然需要安装

而且支持国密算法,JDK需要额外的套件jar支持,笔者就用国际算法吧,通用性强,先使用rsa创建私钥,这里不考虑安全性,就用默认算法长度

openssl genpkey -algorithm RSA -out private.key

然后创建签名请求

openssl req -new -key private.key -out demo.csr

然后生成公钥证书(公钥就是要给出去的)

openssl x509 -req -in demo.csr -signkey private.key -out server.crt 

 也可以查看证书信息

openssl x509 -in server.crt -text -noout

证书配置tomcat(包括嵌入式),nginx,或者ssl服务器即可,demo tomcat、nginx官网很详细

直接报错

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

解决办法

目前通用的办法有2种,让JDK识别信任根证书;忽略认证证书的过程

证书认证过程分析

证书认证在ssl握手的时候,即socket(Linux sock)连接上后就会client hello和server hello,这个时候会传递证书,当然TLS1.2和TLS1.3会有些不同,但是证书的传递是必须的,即服务器公钥传递

SpringCloud使用httpclient的时候,在org.apache.http.conn.ssl.SSLConnectionSocketFactory发起socket的握手

sslsock.startHandshake();

而JDK使用JCE和JSSE的jar来完成SSL的通信,认证过程在JSSE的jar,里面有判断是否TLS1.3,然后使用sun.security.ssl.SSLHandshake,来发送client hello

发送时协商tls版本和加密套件,会发送随机数,用于预主密钥的生成

 发送client hello的信息

然后server发送serverhello回执,协商加密套件,服务端随机数,证书等

serverhello 

keyexchange

进行证书认证

比如微软的证书,证书链和密钥交换算法

调用sun.security.validator.PKIXValidator,对证书链进行校验,和JDK自己内置的证书逐一对比,读取根证书

比如demo这里就从jdk读取到了根证书

然后sun.security.validator.Validator,检查host证书

加入JDK信任

实际上根据JDK的证书认证原理,只需要把JDK没有内置的根证书加入信任,或者把那个证书加入信任即可,建议信任那个证书,而非根证书

可以使用keytool工具导入,这位博主写的这个很好,直接用openssl工具导出证书,很多教程都是通过浏览器导出证书,这个在很多生产环境是不现实的。

将所访问的SSL站点证书添加至JVM。
echo -n |openssl s_client -connect 182.242.198.40:5000|sed -ne'/BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > xxxxx.cert
此命令获取服务端证书链。
keytool -importcert -alias 182.242.198.40-1 -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file xxxxx.cert
————————————————
版权声明:本文为CSDN博主「呆呆鸟哈密瓜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37084673/article/details/108597947

笔者使用这个实际上也跳进坑里了,并不是命令的坑,而是JAVA_HOME,命令执行的JAVA_HOME和实际程序运行的JAVA_HOME未必是同一个,这个一定要在ps aux|grep java后根据实际执行的进程的JAVA_HOME执行命令

忽略认证

忽略信任这个实际上SpringCloud官方就已经支持,就是自己写一个信任manager类,然后里面什么都不做

然后载入sslcontext,这样每次请求就不去信任证书了,安全等级会降低,可以安装zuul的请求放开某一个url的信任,这样可以精确限制,对于SpringCloud只需要配置disableSslValiadation即可

JAVA程序自动加入信任

使用代码加载,最开始源代码来源于InstallCert,不过我改了一下

package com.feng.zuul.demo.connection;

/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class InstallCert {

    // 我们要访问的HTTPS服务,如访问 https://www.bing.com
    public static final String hostName = "cn.bing.com";

    private static final char SEP = File.separatorChar;

    public static void main(String[] args) throws Exception {
        String host = hostName;
        int port = 443;
        char[] passphrase = "changeit".toCharArray();

        File file = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security" + SEP + "cacerts");
        if (!file.exists() || !file.isFile()) {
            System.out.println("jre lib security cacerts is not existed or not file in jdk");
            return;
        }

        System.out.println("Loading KeyStore " + file + "...");
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        try (InputStream in = Files.newInputStream(file.toPath())) {
            ks.load(in, passphrase);
        }

        SSLContext context = SSLContext.getInstance("TLS");
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
        SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
        context.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory factory = context.getSocketFactory();

        System.out.println("Opening connection to " + host + ":" + port + "...");
        SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
        socket.setSoTimeout(10000);
        try {
            System.out.println("Starting SSL handshake...");
            socket.startHandshake();
            System.out.println();
            System.out.println("No errors, certificate is already trusted");
            //当然不可能执行这个,因为我们的证书校验getAcceptedIssuers定义直接抛异常了
            return;
        } catch (SSLException e) {
            System.out.println();
            e.printStackTrace(System.out);
        } finally {
            socket.close();
        }

        X509Certificate[] chain = tm.chain;
        if (chain == null) {
            System.out.println("Could not obtain server certificate chain");
            return;
        }
        System.out.println("Server sent " + chain.length + " certificate(s):");
        System.out.println();

        for (X509Certificate cert : chain) {
            Collection<List<?>> nativeNames = cert.getSubjectAlternativeNames();
            if (nativeNames == null || nativeNames.isEmpty()) continue;
            String alias = host + "-" + cert.getSerialNumber();
            ks.setCertificateEntry(alias, cert);
            System.out.println();
            System.out.println(cert);
            System.out.println();
            System.out.println("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'");
        }

        try (OutputStream out = Files.newOutputStream(file.toPath());) {
            ks.store(out, passphrase);
            System.out.println("Added all certificate to keystore");
        }
    }

    private static class SavingTrustManager implements X509TrustManager {

        private final X509TrustManager tm;
        private X509Certificate[] chain;

        SavingTrustManager(X509TrustManager tm) {
            this.tm = tm;
        }

        public X509Certificate[] getAcceptedIssuers() {
            throw new UnsupportedOperationException();
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            throw new UnsupportedOperationException();
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            this.chain = chain;
            tm.checkServerTrusted(chain, authType);
        }
    }

}

这个加载的证书,可以被JDK初始化载入,那么信任的证书必须重启应用才能生效,那么用什么办法不重启呢。方法来源于org.springframework.cloud.configuration.SSLContextFactory,还是Spring实现的,照搬过来即可,不过Spring是静态文件加载,我们可以动态代码加载

HTTPS是sslcontext去发起的,那么把证书动态给创建这个上下文即可

	public SSLContext createSSLContext() throws GeneralSecurityException, IOException {
		SSLContextBuilder builder = new SSLContextBuilder();
		char[] keyPassword = properties.keyPassword();
		KeyStore keyStore = createKeyStore();

		try {
            // 载入文件
			builder.loadKeyMaterial(keyStore, keyPassword);
		}
		catch (UnrecoverableKeyException e) {
			if (keyPassword.length == 0) {
				// Retry if empty password, see
				// https://rt.openssl.org/Ticket/Display.html?id=1497&user=guest&pass=guest
				builder.loadKeyMaterial(keyStore, new char[] { '\0' });
			}
			else {
				throw e;
			}
		}

		KeyStore trust = createTrustStore();
		if (trust != null) {
            // 加入信任
			builder.loadTrustMaterial(trust, null);
		}

		return builder.build();
	}

改造一下:在自定义connectionmanager的bean增加信任证书加载的逻辑,把InstallCert的证书传过来,当然可以在初始化或者动态实时处理

比如应用启动初始化

@Configuration
public class DemoConfiguration {

    @Bean
    @ConditionalOnProperty(name = "zuul.ssl.ignore.host", havingValue = "true", matchIfMissing = false)
    public ApacheHttpClientConnectionManagerFactory initApacheHttpClientConnectionManagerFactory(){
        ZuulApacheHttpClientConnectionManagerFactory clientConnectionManagerFactory = new ZuulApacheHttpClientConnectionManagerFactory();
        clientConnectionManagerFactory.setIgnoreHostVerify(true);
        return clientConnectionManagerFactory;
    }
    @Bean
    @ConditionalOnBean(InstallCert.class)
    @ConditionalOnProperty(name = "zuul.ssl.ignore.host", havingValue = "true", matchIfMissing = false)
    public ApacheHttpClientConnectionManagerFactory initApacheHttpClientConnectionManagerFactory(InstallCert installCert){
        ZuulApacheHttpClientConnectionManagerFactory clientConnectionManagerFactory = new ZuulApacheHttpClientConnectionManagerFactory();
        clientConnectionManagerFactory.setIgnoreHostVerify(true);
        clientConnectionManagerFactory.setInstallCert(installCert);
        return clientConnectionManagerFactory;
    }

    @Bean
    public InstallCert initCert(){
        return new InstallCert();
    }

可以通过各种方式控制,来达到自动JDK不识别证书的信任,还可以根据sslcontext的创建逻辑,实现租户隔离,达到我们按想法定制的目的。 

总结

实际上证书的认证就是链式认证,加入根证书链,因为根证书是信任的,CA机构是认可的,那么CA颁发的根证书是信任的,经常报道的Chrome移除xxx机构颁发的根证书,表示这些证书链下的证书不信任了,毕竟公钥和私钥任何证书都能生成,证书链也可以仿造。

在服务器的应用中,如果证书验证不通过可以加入证书认证的过程,如果是IP访问,那么host认证失败就让IP的host来验证,如果国密算法不支持就加入国密支持包,实在不想认证也可以跳过认证,浏览器一般是飘红,程序无感知,前提是需要知道安全性,实际上绝大多数内网络证书都是不被认证的,除非定制操作系统配置或者JDK等中间件配置,可根据实际情况来决定解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1118210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity⭐️Win和Mac安卓打包环境配置

文章目录 🟥 配置Android SDK1️⃣ 配置 SDK Platforms2️⃣ 配置 SDK Tools🎁 Android SDK Build-Tools🎁 Android SDK Command-line Tools(latest)🎁 Android SDK Tools(Obsolete)🟧 配置NDK🟩 配置JDK前情提示: 此方法适用于Windows/Mac 在配置时注意开启 🪜 …

shell变量之学习笔记

shell变量之学习笔记 Shell变量概念1 shell变量分类&#xff1a;2 变量的赋值3 变量赋值格式&#xff1a;4 变量命名方式5 变量声明6 变量引用7 变量清除8 变量只读9 内部参数变量10 位置参数变量11 退出和返回状态12 命令替换13 read命令14 字符串长度与截取15 字符串替换16 变…

FL studio21永久激活码 附带一键下载安装包

玩音乐的朋友&#xff0c;对FL studio肯定不陌生&#xff0c;目前最新的版本是FL studio21&#xff0c;这是一款非常强大且专业的音频制作软件&#xff0c;而且还可以编曲、剪辑、录音、混音等等之类的创作操作&#xff0c;使你的计算机成为一个全功能录音室。下面小编就来和大…

15.Tensor Product vs. Kronecker Product

此处是为澄清她两的区别&#xff0c; 这两个事物 都用的相同的符号表示&#xff0c; 即这个圈数符号&#xff0c; 它在数学中有许多不同的含义&#xff0c; 本文讨论的是&#xff1a;“张量积”&#xff0c;它是对张量的运算&#xff1b; 以及“Kronecker ”积&#xff0c;…

C#WPFPrism框架模块化应用实例

本文实例演示C#WPFPrism框架模块化应用实例。 首先创建WPF项目,修改App相关文件内容,以便使用prism。 一、添加模块 解决方案中添加ModuleA和ModuleB两个项目 删除不用的窗体,添加自定义窗体 修改ModuleA和ModuleB的输出类型

最近又火了!吴恩达《生成式 AI》重磅发布!

吴恩达教授可能是许多人接触 AI 的启蒙课导师吧&#xff0c;在过去的十多年中&#xff0c;他的《Machine Learning》课程已经对数百万的学习者产生了积极影响。 而随着 ChatGPT 的推出&#xff0c;大模型和各类生成式人工智能&#xff08;GenAI&#xff09;技术在行业内外备受…

激活WinEdt 11.1

激活WinEdt 11.1 打开WinEdt 11.1&#xff0c;点击help 点击Register WinEdtname输入&#xff1a;*60[20220501] Warez_Down [RU-BOARD] (100 users)Code输入&#xff1a;4049089118892183088 即可激活。 参考文章https://blog.csdn.net/j_l_sheng/article/details/125456662

内存的基础知识

一、概述 1.内存&#xff1a; 存放数据&#xff0c;为了缓和CPU与硬盘之间的速度差异&#xff0c;程序执行前会先放入内存中再让CPU处理。 由存储单元(存放数据的最小单元&#xff0c;每个单元都会对应一个地址)构成 2.常用数量单位&#xff1a; 1K(千)2的10次方 1M(兆)2的20次…

基于springboot实现藏区特产销售平台项目【项目源码+论文说明】计算机毕业设计

基于springboot实现藏区特产销售平台演示 摘要 “互联网”的战略实施后&#xff0c;很多行业的信息化水平都有了很大的提升。但是目前很多藏区特产销售信息仍是通过人工管理的方式进行&#xff0c;需要在各个岗位投入大量的人力进行很多重复性工作&#xff0c;使得对人力物力造…

Python Django教程之实现待办事项应用程序

Django是一个基于Python Web框架的高级Web框架&#xff0c;允许快速开发和干净&#xff0c;务实的设计。本文将创建一个待办事项应用程序&#xff0c;以了解Django的基础知识&#xff0c;感兴趣的可以尝试一下。今天&#xff0c;我们将创建一个待办事项应用程序&#xff0c;以了…

基于springboot实现4S店车辆管理系统项目【项目源码+论文说明】

基于springboot实现4S店车辆管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&am…

leetcode 105. 从前序与中序遍历序列构造二叉树

2023.10.21 本题需要根据前序遍历序列和中序遍历序列来构造出一颗二叉树。类似于从中序与后序遍历序列构造二叉树 。使用递归&#xff0c; java代码如下&#xff1a; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

建筑模板价格多少钱一张?

建筑模板是建筑施工中常用的一种材料&#xff0c;它的价格对于建筑行业来说非常重要。根据搜索结果&#xff0c;以下是关于建筑模板价格的具体信息&#xff1a; 1. 建筑模板尺寸和价格&#xff1a; - 常见的建筑模板尺寸有两种&#xff1a;2440mm 1220mm和1830mm 915mm - 一般…

个人微信号管理工具哪个好?

先来看看微信个人号管理工具的应用场景和功能。 下面主要从微信个人号管理工具中我觉得比较好用的功能进行讲解&#xff1a; 1加粉功能 私域流量池搭建第一步&#xff0c;导入用户。 导入数据&#xff08;微信号或手机号&#xff09;&#xff0c;设置加人任务&#xff0c;每天会…

OpenCV中world模块介绍

OpenCV中有很多模块&#xff0c;模块间保持最小的依赖关系&#xff0c;用户可以根据自己的实际需要链接相关的库&#xff0c;而不需链接所有的库&#xff0c;这样在最终交付应用程序时可以减少总库的大小。但如果需要依赖OpenCV的库太多,有时会带来不方便&#xff0c;此时可以使…

SLAM进阶(九)---- cannot open shared object file问题

1 为什么会遇到这个问题 我们在 2 查看问题所在 我的项目依赖于VTK 7.1.1&#xff0c;PCL 1.9.1。项目可以完成编译&#xff0c;但是不能执行。即使用动态库编译链接stereo_inertial_tum_vi_old.cc后&#xff0c;得到名为stereo_inertial_tum_vi_old的可执行程序。但是在运行st…

哪些企业适合做私域?私欲怎么做成效大?

什么是私欲 简单直白来说&#xff0c;就是不用花钱就可以触达客户的渠道。私域流量就是私人的流量&#xff08;不用花钱&#xff09;。 哪些企业适合做私域&#xff1f; 》复购率高 比如美妆护肤产品行业、餐饮等快消品行业。 可通过群发推广消息、朋友圈营销和在社群里不断进…

Breach 1.0 靶机

Breach 1.0 环境配置 设置 VMware 上的仅主机模式网卡&#xff0c;勾选 DHCP 自动分配 IP&#xff0c;将子网改为 192.168.110.0/24 将靶机和 kali 连接到仅主机网卡 信息搜集 存活检测 详细扫描 后台网页扫描 网页信息搜集 Initech被入侵&#xff0c;董事会投票决定引入…

二、UI入门

1. QWidget类 QWidget类是Qt所有图形用户界面&#xff08;组件&#xff09;的基类&#xff0c;因此QWidget类内部规定了所有最基础的UI相关功能。例如以下成员&#xff1a; ● width : const int 宽度&#xff08;单位&#xff1a;像素&#xff0c;后文同&#xff09; Qt中的…

基于SegFormer的改进语义分割该网络

摘要 场景解析是无人驾驶领域的一个关键任务&#xff0c;但是传统的语义分割网络往往只关注于提取更深层次的图像语义信息而忽略了全局信息对图像分割任务的重要性。另外随着图像在深层次卷积网络中的传递&#xff0c;卷积核天然的滤波作用会使得图像的边缘趋于平滑而丢失细节特…