Java SSL/TLS证书认证逻辑

前言

最近做项目使用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 availablefinal 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 ZuulApacheHttpClientConnectionManagerFactoryimplements 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);}@Overridepublic 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 {@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s)throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s)throws CertificateException {}@Overridepublic 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.compublic 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=guestbuilder.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;}@Beanpublic InstallCert initCert(){return new InstallCert();}

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

总结

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

emqx 启动正常,但是1883端口无法telnet,emqx无法正常工作

emqx一直正常工作&#xff0c;后面突然就不工作了&#xff0c;查找日志&#xff0c;发现报错说设备空间不足&#xff0c;但是我记得华为云SSD从40G扩容到500G&#xff0c;不至于空间不足&#xff0c;于是运行df -Dh确实显示只有40G&#xff0c;运行lsblk确实有500G&#xff0c;…

基于Arrow的轻量线程池

基于Arrow的轻量线程池 大家好&#xff0c;我是光城&#xff0c;最近花了几周业余时间&#xff0c;开发出这款轻量线程池&#xff0c;代码也全部开源啦&#xff0c;欢迎大家star。 本线程池的设计与实现会有涉及非常多的知识&#xff0c;这些内容也都会以视频的方式分享在知识星…

每个epoch的溯源(MNE)

每个epoch的溯源&#xff1a; from mne.minimum_norm import apply_inverse_epochs stcs apply_inverse_epochs(epochs,inverse_operator,lambda2,method,pick_ori"normal"# naveevoked.nave, )

从零开始构建基于YOLOv5的目标检测系统

本博文从零开始搭建基于YOLOv5模型的目标检测系统&#xff08;具体系统参考本博主的其他博客&#xff09;&#xff0c;手把手保姆级完成环境的搭建。 &#xff08;1&#xff09;首先Windows R输入cmd命令后打开命令窗口&#xff0c;进入项目目录&#xff0c;本博文以野生动物…

交换机控制在同一个网段内的终端,用hybrid接口实现不同的IP通和不通。

实验效果&#xff1a;pc1和pc2不能通&#xff0c;但pc1和pc2分别可以和pc3通。 通过这个实验可以彻底掌握数据包在交换机上的进去的类型状态。 sw1配置&#xff1a; [sw1]dis current-configuration sysname sw1 vlan batch 10 20 100 interface GigabitEthernet0/0/1 port h…

计算机服务器中了勒索病毒怎么解决,勒索病毒解密流程,数据恢复

计算机服务器中了勒索病毒是一件非常令人头疼的事情&#xff0c;勒索病毒不仅会加密企业服务器中的数据&#xff0c;还会对企业计算机系统带来损害&#xff0c;严重地影响了企业的正常运转。最近&#xff0c;云天数据恢复中心工程师总结了&#xff0c;今年以来网络上流行的勒索…

Vue3中使用富文本编辑器

在vue3中我们可以使用wangeditor/editor、wangeditor/editor-for-vue来实现其功能 npm地址&#xff1a;https://www.npmjs.com/package/wangeditor/editor-for-vue/v/5.1.12?activeTabreadme 官网&#xff1a;Editor 1. 安装 pnpm add wangeditor/editor # 或者 npm inst…

卷积神经网络CNN学习笔记-卷积计算Conv2D函数的理解

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.Conv2D函数解析9.conv2d代码9.1 stride19.2 stride2 参考文章 1.全连接层存在的问题 在全连接层中&#xff0c;相邻层的神经元全部连接…

饲料化肥经营商城小程序的作用是什么

我国农牧业规模非常高&#xff0c;各种农作物和养殖物种类多&#xff0c;市场呈现大好趋势&#xff0c;随着近些年科学生产养殖逐渐深入到底层&#xff0c;专业的肥料及饲料是不少从业者需要的&#xff0c;无论城市还是农村都有不少经销店。 但在实际经营中&#xff0c;经营商…

Jetson nano 安装Ubuntu20.04系统

一、下载Ubuntu20.04镜像 下载地址&#xff1a;点击 二、格式化SD卡 &#xff08;1&#xff09;工具&#xff1a;SDFormatter &#xff08;2&#xff09;工具下载-百度网盘&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1DcwsGzmqrWwFmzpCV7VCyA 提取码&#xff1a…

bp(back propagation)

文章目录 定义过程前向传播计算过程计算损失函数&#xff08;采用均方误差MSE&#xff09;反向传播误差&#xff08;链式法则&#xff09;计算梯度更新参数 简单实例 定义 反向传播全名是反向传播误差算法&#xff08;Backpropagation&#xff09;&#xff0c;是一种监督学习方…

python二次开发Solidworks:修改实体尺寸

立方体原始尺寸&#xff1a;100mm100mm100mm 修改后尺寸&#xff1a;10mm100mm100mm import win32com.client as win32 import pythoncomdef bin_width(width):myDimension Part.Parameter("D1草图1")myDimension.SystemValue width def bin_length(length):myDime…

【吞噬星空】又被骂,罗峰杀人目无法纪,但官方留后手,增加审判戏份

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫吞噬星空资讯。 吞噬星空动画中&#xff0c;罗峰复仇的戏份&#xff0c;简直是帅翻了&#xff0c;尤其是秒杀阿特金三大巨头&#xff0c;让人看的也是相当的解气&#xff0c;相当的爽&#xff0c;一点都不拖沓&#x…

TCP为什么需要三次握手和四次挥手?

一、三次握手 三次握手&#xff08;Three-way Handshake&#xff09;其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包 主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备 过程如下&#xff…

力扣每日一题51:N皇后问题

题目描述&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问…

bitbucket.org 用法

这个网站需要魔法&#xff0c;注册完成后添加厂库时间2023.10 图1 图2 第二张图 &#xff0c;不要.gitignore文件 sourcetree 1,创建前端项目 npm create vitelatest 2.打开vscode创建本地Git 看到Git代提交的文件 sourcetree&#xff0c;新建 已存在的本地厂库 提交到Git 添…

linux基础IO

文章目录 前言一、基础IO1、文件预备知识1.1 文件类的系统调用接口1.2 复习c语言接口 2、文件类的系统调用接口2.1 open系统调用2.2 close系统调用2.3 write系统调用2.4 read系统调用 3、文件描述符3.1 文件描述符fd介绍3.2 文件描述符fd分配规则与重定向3.3 重定向原理3.4输入…

(八)vtk常用类的常用函数介绍(附带代码示例)

vtk中类的说明以及函数使用 https://vtk.org/doc/nightly/html/annotated.html 一、vtkObject派生类 1.vtkPoints 点 InsertNextPoint(double, double, double)&#xff1a;插入点。 2.vtkCellArray 单元数组 InsertNextCell (vtkIdType npts, const vtkIdType *pts)&…

java与c++中的交换方法

最近在写算法的时候&#xff0c;遇到一个问题。 java中编写swap&#xff08;交换&#xff09;方法还需要传入一个数组&#xff0c;但是在c中则不需要。 可以看到&#xff0c;在没有传入数组进行交换数组元素的时候&#xff0c;交换前与交换后的值是一样的。 而在c中&#xff…

笔记:绘图进阶

主要功能&#xff1a; 双坐标轴多子图共用一个横坐标横坐标时间刻度设置&#xff08;方便&#xff09; # -*- coding: utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdatesif __name__ __main__:# 风速da…