文档章节

HttpClient执行Https请求与分析

ksfzhaohui
 ksfzhaohui
发布于 2017/06/11 21:08
字数 2044
阅读 544
收藏 2
点赞 0
评论 0

Https介绍
HTTPS:为了保证隐私数据能加密传输,采用SSL/TLS协议用于对HTTP协议传输的数据进行加密,也就是HTTPS。
SSL:SSL(Secure Sockets Layer)协议是由网景公司设计,后被IETF定义在RFC 6101中,目前的版本是3.0。
TLS:TLS可以说是SSL的改进版。是由IETF对SSL3.0进行了升级而出现的,定义在RFC 2246,实际上我们现在的HTTPS都是用的TLS协议。

HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息;TLS/SSL中使用了非对称加密,对称加密以及HASH算法,其中非对称加密算法用于在握手过程中加密生成的密码,对称加密算法用于对真正传输的数据进行加密,而HASH算法用于验证数据的完整性;TLS握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。

SSL/TLS版本
1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布;
1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞;
1996年,SSL 3.0版问世,得到大规模应用;
1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版;
2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。最新的变动是2011年TLS 1.2的修订版。

JDK对SSL/TLS版本的支持
JDK 8(March 2014 to present):TLSv1.2 (default),TLSv1.1,TLSv1,SSLv3
JDK 7(July 2011 to present):TLSv1.2,TLSv1.1,TLSv1 (default),SSLv3
JDK 6(2006 to end of public updates 2013):TLS v1.1 (JDK 6 update 111 and above),TLSv1 (default),SSLv3
更多详细介绍:https://blogs.oracle.com/java-platform-group/diagnosing-tls%2c-ssl%2c-and-https

准备
JDK:jdk1.7.0_80
Tomcat:apache-tomcat-7.0.28

配置Tomcat支持Https
1.生成服务器证书

C:\Users\Administrator.SKY-20170404CXG>cd C:\Program Files\Java\jdk1.7.0_80\bin
 
C:\Program Files\Java\jdk1.7.0_80\bin>keytool -genkey -v -alias tomcat -keyalg R
SA -keystore E:\tomcat.keystore
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  localhost
您的组织单位名称是什么?
  [Unknown]:  codingo
您的组织名称是什么?
  [Unknown]:  codingo
您所在的城市或区域名称是什么?
  [Unknown]:  nanjing
您所在的省/市/自治区名称是什么?
  [Unknown]:  jiangsu
该单位的双字母国家/地区代码是什么?
  [Unknown]:  zhongguo
CN=localhost, OU=codingo, O=codingo, L=nanjing, ST=jiangsu, C=zhongguo是否正确?
  [否]:  y
 
正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 90 天
):
         CN=localhost, OU=codingo, O=codingo, L=nanjing, ST=jiangsu, C=zhongguo
输入 <tomcat> 的密钥口令
        (如果和密钥库口令相同, 按回车):
[正在存储E:\tomcat.keystore]

密钥为:111111
名字与姓氏:必须是TOMCAT部署主机的域名或者IP,本地测试直接用localhost,如果不这样设置httpclient4测试的时候会出现如下错误:

Exception in thread "main" javax.net.ssl.SSLException: hostname in certificate didn't match: <localhost> != <codingo>

最终生成的服务器证书存储在E:\tomcat.keystore,以上的工作是为Tomcat配置支持https协议做准备。

2.修改配置
Tomcat 安装目录下/conf/server.xml中做如下配置:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           keystoreFile="E:\\tomcat2.keystore" keystorePass="111111"
           clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1"/>

keystoreFile:服务器证书
keystorePass:证书密码
sslProtocol:要使用的ssl协议,一个值代表多个协议版本,默认值TLS,可选值如下:

SSL     :TLSv1
SSLv2   :不可用
SSLv3   :TLSv1
TLS     :TLSv1
TLSv1   :TLSv1
TLSv1.1 :TLSv1,TLSv1.1
TLSv1.2 :TLSv1,TLSv1.1,TLSv1.2

注:以上可选值也要根据具体使用的jdk版本,参考:JDK对SSL/TLS版本的支持,对应jdk版本不支持启动会出现如下错误:

严重: Failed to initialize end point associated with ProtocolHandler ["http-nio-8443"]
java.security.NoSuchAlgorithmException: TLSv1.1 SSLContext not available

以上值可以通过如下代码获取:

public static void main(String[] args) throws NoSuchAlgorithmException, IOException, KeyManagementException {
    SSLContext sslcontext = SSLContext.getInstance("TLSv1.1");
    sslcontext.init(null, new TrustManager[] { new HttpClient3TrustManager() }, new java.security.SecureRandom());
    SSLSocket sslsocket = (SSLSocket) sslcontext.getSocketFactory().createSocket();
    String supportedProtocols[] = sslsocket.getSupportedProtocols();
    String enabledProtocols[] = sslsocket.getEnabledProtocols();
 
    String sp = "";
    String ep = "";
    for (String p : supportedProtocols) {
        sp = sp + p + ",";
    }
    for (String p : enabledProtocols) {
        ep = ep + p + ",";
    }
    System.err.println("SupportedProtocols = " + sp + " enabledProtocols = " + ep);
}

HttpClient3TrustManager类

public class HttpClient3TrustManager implements X509TrustManager {
 
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }
 
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }
 
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[] {};
    }
}

sslEnabledProtocols:支持HTTPS连接的SSL协议,用逗号分隔;如果设置值支持的协议就为当前值,否则默认值:TLSv1,TLSv1.1,TLSv1.2

更多参考:
https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext

浏览器测试
打开chrome浏览器输入地址:https://localhost:8443/,如下图所示:

Httpclient3测试
maven引入httpclient3:

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

HttpClient3测试类:

public class HttpClient3 {
 
    public static void main(String[] args) {
        System.setProperty("javax.net.debug", "all");
        String y = doGet("https://localhost:8443/");
        System.out.println(y);
    }
 
    public static String doGet(String url) {
        StringBuffer response = new StringBuffer();
        HttpClient client = new HttpClient();
        HttpMethod method = new GetMethod(url);
        BufferedReader reader = null;
        try {
            if (url.startsWith("https")) {
                Protocol myhttps = new Protocol("https", new HttpClient3SSLProtocolSocketFactory(), 443);
                Protocol.registerProtocol("https", myhttps);
            }
            client.executeMethod(method);
            if (method.getStatusCode() == HttpStatus.SC_OK) {
                reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(), "utf-8"));
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            }
        } catch (URIException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
            }
            method.releaseConnection();
        }
        return response.toString();
    }
}

System.setProperty(“javax.net.debug”, “all”); 方便了解通过SSL协议建立网络连接时的全过程;

HttpClient3SSLProtocolSocketFactory类:

public class HttpClient3SSLProtocolSocketFactory implements ProtocolSocketFactory {
 
    private SSLContext sslcontext = null;
 
    private SSLContext createSSLContext() {
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContext.getInstance("TLSv1");
            sslcontext.init(null, new TrustManager[] { new HttpClient3TrustManager() }, new java.security.SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslcontext;
    }
 
    private SSLContext getSSLContext() {
        if (this.sslcontext == null) {
            this.sslcontext = createSSLContext();
        }
        return this.sslcontext;
    }
 
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
            throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
    }
 
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }
 
    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
            throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
    }
 
    public Socket createSocket(String host, int port, InetAddress localAddress, int localPort,
            HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
        if (params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }
        SocketFactory socketfactory = getSSLContext().getSocketFactory();
        return socketfactory.createSocket(host, port, localAddress, localPort);
    }
}

来看一下SSL双向认证的全过程(图片来自网上):

更多详细的介绍wiki:传输层安全协议

下面以上图SSL认证过程,来看具体日志输出,具体模拟几个环境

环境一:
server:jdk1.7,tomcat:apache-tomcat-7.0.28,server.xml配置:sslProtocol=”TLSv1.1″
client:jdk1.7,SSLContext.getInstance(“TLSv1.2”)
运行测试程序,部分日志如下:

*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1496977933 bytes = { ... }
Session ID:  {}
Cipher Suites: []
Compression Methods:  { 0 }
....更多细节运行查看
***

客户端告诉服务器:支持的协议版本:TLSv1.2,一个客户端生成的随机数,支持的加密方法,支持的压缩方法;

*** ServerHello, TLSv1.2
RandomCookie:  GMT: 1496981693 bytes = { ... }
Session ID:  {...}
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Compression Method: 0
....更多细节运行查看
***

服务器回应客户端:确认使用的加密通信协议版本TLSv1.2,一个服务器生成的随机数,确认使用的加密方法,服务器证书;

其他步骤参考上图或者wiki,此处不在列出。

客户端使用TLSv1.2,服务器sslProtocol=”TLSv1.1″,最终确认的通讯版本是TLSv1.2,sslProtocol参数并没有限制TLS的版本,真正起作用的是sslEnabledProtocols参数;

环境二:
server:jdk1.7,tomcat:apache-tomcat-7.0.28,server.xml配置:sslProtocol=”TLS”,sslEnabledProtocols=”TLSv1.1″
client:jdk1.7,SSLContext.getInstance(“TLSv1.2”)
运行测试程序,部分日志如下:

	
*** ClientHello, TLSv1.2
*** ServerHello, TLSv1.1

客户端使用TLSv1.2,服务器端设置了sslEnabledProtocols=”TLSv1.1″,最终以TLSv1.1为准

环境三:
server:jdk1.7,tomcat:apache-tomcat-7.0.28,server.xml配置:sslProtocol=”TLS”,sslEnabledProtocols=”TLSv1.1″
client:jdk1.7,SSLContext.getInstance(“TLSv1”)
客户端报如下错误:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

如果配置protocol=”org.apache.coyote.http11.Http11Protocol”,异常如下:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

其他web服务器也可能出现如下异常:

javax.net.ssl.SSLException: Received fatal alert: protocol_version

原因分析:客户端设置的版本低于sslEnabledProtocols中指定的版本

Httpclient4测试
maven引入httpclient4:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.3.6</version>
</dependency>

HttpClient4测试类:

public class HttpClient4 {
 
    public static void main(String[] args) throws Exception {
        System.setProperty("javax.net.debug", "all");
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
 
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
                new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        HttpGet get = new HttpGet();
        get.setURI(new URI("https://localhost:8443/"));
        httpClient.execute(get);
    }
}

总结
介绍了ssl/tls相关概念,配置tomcat7用来支持https,然后以httpclient3和4为客户端忽略证书验证访问服务器端,通过日志查看ssl/tls握手流程;并且模拟了多种环境用来测试ssl/tls版本,以及可能出现的一些问题。

© 著作权归作者所有

共有 人打赏支持
ksfzhaohui

ksfzhaohui

粉丝 296
博文 126
码字总数 153828
作品 3
南京
高级程序员
关于HttpClient重试策略的研究

原文出处:kingszelda 一、背景 由于工作上的业务本人经常与第三方系统交互,所以经常会使用HttpClient与第三方进行通信。对于交易类的接口,订单状态是至关重要的。 这就牵扯到一系列问题:...

kingszelda ⋅ 04/25 ⋅ 0

使用httpClient 调起https url接口

遇到的问题* 1、ssl证书信任,解决方式信任所有证书 2、生成请求体调用httpPost.setEntity()时输出的参数格式有误,有多种Entity可以选择(常用 StringEntity、UrlEncodedFormEntity、FileE...

梦魂清风 ⋅ 05/10 ⋅ 0

聊聊spring cloud的PreserveHostHeaderGatewayFilter

序 本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gatew......

go4it ⋅ 06/14 ⋅ 0

Httpclient报Timeout waiting for connection from pool 异常

下面这段代码在定时一分钟的任务里面执行: public String remoteJsonUTF8(String url) { HttpGet get = null; CloseableHttpResponse response = null; String json = null; CloseableHttpCl......

小小的小小snake ⋅ 05/17 ⋅ 0

聊聊spring cloud gateway的NettyConfiguration

序 本文主要研究下spring cloud gateway的NettyConfiguration NettyConfiguration spring cloud gateway使用的是reactor的httpclient,其通过nettyClientOptions这个bean来进行构造options,......

go4it ⋅ 06/03 ⋅ 0

大家都用什么工具发起http请求的呢?

我以前喜欢用apache的 httpClient ,公司用jersey。听经理说jersey的性能好,是真的吗?我在网上并没有搜到相关的性能比较,java9也带了一个httpClient,不知性能对比起来又如何?...

暗中观察 ⋅ 04/22 ⋅ 0

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 昨天 ⋅ 0

聊聊spring cloud gateway的RemoveHopByHopHeadersFilter

序 本文主要研究一下spring cloud gateway的RemoveHopByHopHeadersFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway......

go4it ⋅ 05/30 ⋅ 0

聊聊spring cloud gateway的LoadBalancerClientFilter

序 本文主要研究一下spring cloud gateway的LoadBalancerClientFilter GatewayLoadBalancerClientAutoConfiguration spring-cloud-gateway-core-2.0.0.RELEASE-sources.jar!/org/springfram......

go4it ⋅ 06/20 ⋅ 0

聊聊spring cloud gateway的streaming-media-types属性

序 本文主要研究下spring cloud gateway的streaming-media-types属性 配置 配置说明 GatewayProperties spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gatew......

go4it ⋅ 06/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Linux中的端口大全

1 被LANA定义的端口 端口 名称 描述 1 tcpmux TCP 端口服务多路复用 5 rje 远程作业入口 7 echo Echo 服务 9 discard 用于连接测试的空服务 11 systat 用于列举连接了的端口的系统状态 13 d...

寰宇01 ⋅ 11分钟前 ⋅ 0

Confluence 6 如何备份存储文件和页面信息

备份的 ZIP 文件包含有 entities.xml,这个 XML 文件包含有 Confluence 的所有页面内容和存储附件的目录。 备份 Zip 文件结构 页面的附件是存储在附件存储目录中的,通过页面和附件 ID 进行识...

honeymose ⋅ 14分钟前 ⋅ 0

【每天一个JQuery特效】根据状态确定是否滑入或滑出被选元素

主要效果: 本文主要采用slideToggle()方法实现以一行代码同时实现以展开或收缩的方式显示或隐藏被选元素。 主要代码如下: <!DOCTYPE html><html><head><meta charset="UTF-8">...

Rhymo-Wu ⋅ 18分钟前 ⋅ 0

度量.net framework 迁移到.net core的工作量

把现有的.net framework程序迁移到.net core上,是一个非常复杂的工作,特别是一些API在两个平台上还不能同时支持。两个类库的差异性,通过人工很难识别全。好在微软的工程师们考虑到了我们顾...

李朝强 ⋅ 23分钟前 ⋅ 0

请不要在“微服务”的狂热中迷失自我!

微服务在过去几年一直是一个非常热门的话题(附录1)。何为“微服务的疯狂”,举个例子: 众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常...

harries ⋅ 24分钟前 ⋅ 0

oAuth2 升级Spring Cloud Finchley.RELEASE踩坑分享

背景 6.19号,spring团队发布了期待已久的 Spring Cloud Finchley.RELEASE 版本。 重要变化: 基于Spring Boot 2.0.X 不兼容 Spring Boot 1.5.X 期间踩过几个坑,分享出来给大伙,主要是关于...

冷冷gg ⋅ 54分钟前 ⋅ 0

OSChina 周一乱弹 —— 理发师小姐姐的魔法

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @冰冰棒- :分享田馥甄的单曲《My Love》 《My Love》- 田馥甄 手机党少年们想听歌,请使劲儿戳(这里) @Li-Wang :哎,头发又长了。。。又要...

小小编辑 ⋅ 今天 ⋅ 8

Kafka1.0.X_消费者API详解2

偏移量由消费者管理 kafka Consumer Api还提供了自己存储offset的功能,将offset和data做到原子性,可以让消费具有Exactly Once 的语义,比kafka默认的At-least Once更强大 消费者从指定分区...

特拉仔 ⋅ 今天 ⋅ 0

NEO智能合约之发布和升级(二)

接NEO智能合约之发布和升级(一),我们接下来说说智能合约的升级功能。 一 准备工作 合约的升级需要在合约内预先设置好升级接口,以方便在升级时调用。接下来我们对NEO智能合约之发布和升级...

红烧飞鱼 ⋅ 今天 ⋅ 0

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部