20190726 ApacheHttpClient-自签证书与系统证书共存

要使用HTTPClient-4.5.2做一些连接;但是有的域名是使用的自签证书,有的是CA签发证书;同时又不想跳过证书验证又想使用一个HTTPClient;

如果单单实现验证只使用自签证书或者只使用CA证书的域名比较简单;前者只需要new loadTrustMaterial(File file, char[] storePassword).

首先,不妨思考下2分钟:自签证书的12306网站 以前的12306网站使用的就是自签证书,它会提示你下载安装根证书以确保链接的安全,是为什么呢?

首先需要明白jks是什么,HTTPS连接建立过程。

1.jks就是java keyStore,keyStore是个啥东西。不同场景下意义是不同的;在HTTPClient指双向证书验证时需要这个(loadKeyStoreManager),含有公钥和私钥,keyStore一般是用密码保护的,私钥本身自己也是一个密码.

https://stackoverflow.com/questions/23202046/what-is-keystore

2.数字签名技术,CA使用自己的证书私钥加密一个普通企业和机构的一个公钥,这个过程就是签名,签名的结果就是这个企业域名(或软件)的数字证书,服务器把这个东西下发给浏览器,浏览器使用预置在电脑系统的根证书或者浏览器自己的证书库,但基本都是前面那些CA的根证书,用它们的公钥去验证发过来的数字证书是否CA为这个域名签发的,数字证书签发和验证这一过程用到非对称密钥加密;验证通过,浏览器安全地随机一些字符并使用发过来的证书的公钥进行加密,服务器收到后用它的私钥进行解密;然后服务器和浏览器之间就使用这个字符来加密它们之间的流量,这个是对称密钥加密;即加密和解密用一样的密钥或者可以相互计算出来。

大致的流程是这样,有些不太严谨,比如根证书验证数字签名的方法是加密服务器发过来的消息摘要和它自己带过来的签名是否一致,为何需要消息摘要呢(比如MD5)?因为RSA的同态性。

3.TLS是SSL的演进版本,SSL有很多Bug都是基于运输层的安全协议。https://www.differencebetween.com/difference-between-ssl-and-vs-tls/

知道了这些,基本可以明白,可以使用签发自签证书的根证书的公钥来验证服务器发送过来的自签证书了。

从keyStore中取出根证书,如果你不知道根证书的别名,可以遍历 keyStore.aliases()得出来。https://stackoverflow.com/questions/26711731/read-public-key-from-file-in-keystore

java 复制代码
 public static void init() throws Exception {
        rootCerStream = new FileInputStream(loadResourceFile(KEY_STORE_FILE_NAME));
        keyStore = KeyStore.getInstance("JKS");
        keyStore.load(rootCerStream,KEY_STORE_PASSWORD.toCharArray());
        rootCer =  keyStore.getCertificate(ROOT_CER_ALIAS);
    }

获取一个SSLContext来给HTTPClientBuilder来setSSLContext,因为需要SSLConnectionSocketFactory来创建SSL socket

java 复制代码
    public static SSLContext getMixSSLContext() throws Exception{
        SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                for (X509Certificate cer : chain){
                    try {
                        cer.verify(rootCer.getPublicKey());
                    } catch (Exception e){
                        continue;
                    }
                    return true;
                }
                return false;
                //如果不想验证证书,直接return true就行了
            }
        }).build();
        return sslContext;
    }

同时有些时候,可能需要将 builder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE); 比如你直接访问了域名IP,或者你直接访问了ELB而不是那个签发域名,就会提示错误。当然最好的写法是使用new DefaultHostnameVerifier() ps:感觉还是SSLContextBuilder相当方便

java 复制代码
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
....
  builder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
  builder.setSSLHostnameVerifier(new DefaultHostnameVerifier());

当然还有一种解决方法就是将那根证书预置到java的CACert中

https://stackoverflow.com/questions/11143360/ssl-certificate-verification-in-java

了解些背景知识,还有源码,仔细阅读源码,也不是很难的。

相关推荐
隆里卡那唔2 小时前
在dify中通过http请求neo4j时为什么需要将localhost变为host.docker.internal
http·docker·neo4j
~山有木兮3 小时前
LiteHub中间件之限流实现
网络·http·中间件
游戏开发爱好者84 小时前
iOS App首次启动请求异常调试:一次冷启动链路抓包与初始化流程修复
websocket·网络协议·tcp/ip·http·网络安全·https·udp
2501_915106324 小时前
频繁迭代下完成iOS App应用上架App Store:一次快速交付项目的完整回顾
websocket·网络协议·tcp/ip·http·网络安全·https·udp
00后程序员张11 小时前
免Mac上架实战:全平台iOS App上架流程的工具协作经验
websocket·网络协议·tcp/ip·http·网络安全·https·udp
笑衬人心。12 小时前
HTTPS详解:原理 + 加解密过程 + 面试问答
java·网络协议·http·面试·https
bing_15813 小时前
MQTT 和 HTTP 有什么本质区别?
网络·网络协议·http
代码讲故事13 小时前
多种方法实现golang中实现对http的响应内容生成图片
开发语言·chrome·http·golang·图片·快照·截图
未来之窗软件服务14 小时前
通过网页调用身份证阅读器http websocket方法-华视电子————仙盟创梦IDE
网络·网络协议·http·仙盟创梦ide·东方仙盟·硬件接入
醉方休15 小时前
TCP、HTTP/1.1 和HTTP/2 协议
网络协议·tcp/ip·http