美文网首页我爱编程
HttpClient之Https请求

HttpClient之Https请求

作者: 小猪PICK | 来源:发表于2018-03-19 16:47 被阅读0次

1、 Https通信介绍

       Https 即安全的超文本传输协议,最初是由网景公司创建,Https在Http上面提供了一个传输级的安全层,目前安全层所用的协议是SSL(Secure Socket Layer)和其继任者TLS(Transport Layer Security),SSL是一个比较复杂的协议,已有商用和开源的实现版本,例如OpenSSL。所有Http请求和响应数据在传输到网络前都由安全层进行加密,如下图是Https和Http的网络协议层。

       客服端与服务器在建立连接前,需要进行握手,握手过程可分为单向和双向认证两类。

(1)    单向认证

        客服端只对服务端身份进行认证,具体认证过程如下图:

(2)    双向认证

       客服端不仅对服务端身份进行认证,同时服务端也需要客服端发送自己的身份信息,对客服端进行认证,具体认证过程如下图:

2、JSSE介绍

       JSEE 全称Java Secure Socket Extension,提供了一个java版本的SSL 协议的框架和实现,包括数据加密、服务器认证、消息完整性校验及可选的客服端认证等功能。Java应用程序可以借助JSEE,方便地实现Https通信。            在JSEE API中,连接的端点类是SSLSocket和 SSLEngine,下图展示了用于创建SSLSocket和SSLEngine的类:

       了解socket编程的朋友,从图中应该很容易看出,客服端所用的SSLSocket由SSLSocketFactory创建,服务器用的SSLServerSocket由SSLServerSocketFactory创建,这两个factory由SSLContext创建,SSLContext对象创建后需要用KeyManger、TrustManger、SecureRandom进行初始化,分别对本文用到的几个类说明下,对其他类有兴趣的可以参考oracle JSSE官方文档。

       SSLSocket:继承java网络编程中Socket的作用,应用程序通过SSLSocket完成SSL握手、通信数据的收发等;

       SSLEngine:类同SSLSocket,比SSLSocket功能更强大,SSLSocket提供的是阻塞IO模型,SSLEngine能提供非阻塞的IO模型;

        KeyManger:用于管理密钥、证书等,通信的一端通过KeyManager获取密钥、证书传递给通信对方,对方验证证书获取密钥;

        TrustManger:用于管理信任材料,用于验证通信对等方的身份,传递的证书是否合法;

3、HttpClient发送Https请求

        借助JSSE,HttpClient对Https请求提供全面的支持,HttpClient 借助JSSE API创建SSLSocket,用于Https请求,相关的类如下图:

        SSLProtocolSocketFactory类的createSocket方法内部实现是调用SSLSocketFactory的createSocket方法创建SSLSocket的,如下图:

(1)、标准的Https请求实例

标准的Https请求跟Http请求没有任何差异,HttpClient执行请求时依据url来判断是Http还是Https请求,自动进行通信处理,如下实例:

HttpClienthttpclient = new HttpClient();

  GetMethod httpget = newGetMethod("https://www.verisign.com/");

  try {

    httpclient.executeMethod(httpget);

   System.out.println(httpget.getStatusLine());

  } catch (Exception e) {

    e.printStackTrace();

  } finally {

    httpget.releaseConnection();

  }

当客服端通过代理与服务器通信时,与标准请求相比,需要设置与代理服务器进行身份认证的参数,建立SSL隧道的工作由Httpclient完成,应用无须关注,如下实例:

  HttpClient httpclient = new HttpClient();

 httpclient.getHostConfiguration().setProxy("myproxyhost",8080);

  httpclient.getState().setProxyCredentials("my-proxy-realm"," myproxyhost",

  newUsernamePasswordCredentials("my-proxy-username","my-proxy-password"));

  GetMethod httpget = newGetMethod("https://www.verisign.com/");

  try {

    httpclient.executeMethod(httpget);

    System.out.println(httpget.getStatusLine());

  } catch (Exception e) {

    e.printStackTrace();

  } finally {

    httpget.releaseConnection();

  }

(2)、定制的Https请求

一般场景下,标准Https请求能满足应用需求,有些应用场景需要对SSL协议细节进行定制,例如客服端接收服务器自签名的证书、双向认证、或用其他第三方SSL库替换JSSE的实现等,可按照如下步骤实现定制Https请求:

第一步,提供一个定制的套接字工厂类,该类实现 org.apache.commons.

httpclient.protocol.SecureProtocolSocketFactory接口,该factory负责创建SSLSocket, 实现定制就在这步,后续几步是描述将定制的Socket用于Https请求中;

第二步,第一步创建的SocketFactory实例化 org.apache.commons.httpclient.protocol.Protocol类型对象,实例化时需要指明协议和端口字段,如下实例代码:

Protocolmyhttps = new Protocol("https", new MySSLSocketFactory(), 443);

第三步,可以请求的主机或协议类设置协议对象,当针对主机设置时,当请求注册的主机时,会用定制SocketFactory创建SSLSocketSocket,代码实例如下:

HttpClienthttpclient = new HttpClient();

httpclient.getHostConfiguration().setHost("www.whatever.com",443, myhttps);

GetMethodhttpget = new GetMethod("/");

try {

  httpclient.executeMethod(httpget);

  System.out.println(httpget.getStatusLine());

} catch(Exception e) {

  e.printStackTrace();

} finally{

  httpget.releaseConnection();

}

当针对https协议设置协议对象时,即所有https请求都会用定制的SocketFactory创建SSLSocketSocket,代码实例如下:

Protocol.registerProtocol("https",

newProtocol("https", new MySSLSocketFactory(), 443));

HttpClienthttpclient = new HttpClient();

GetMethodhttpget = new GetMethod("https://www.whatever.com/");

try {

  httpclient.executeMethod(httpget);

  System.out.println(httpget.getStatusLine());

} catch(Exception e) {

e.printStackTrace();

}  finally {

  httpget.releaseConnection();

}

针对https协议设置协议对象这种方式需要慎用,需要考虑应用所有的https请求是否都是可用相同的定制SSLSocket,可跟踪registerProtocol方法实现,在项目中就遇到乱用这种方式导致的问题:公司有个系统需要调用微信和支付宝相关的接口,两者都是Https请求,调用微信接口需要定制Socket,错误地针对https协议注册定制Socket,导致调用微信接口加载本地证书失败时,其他线程调用支付宝接口也出现失败,报错的异常堆栈一致。

(3)、开源的定制SocketFactory实例

Apath开源了相关的定制实例,可以参考EasySSLProtocolSocketFactoryStrictSSLProtocolSocketFactoryAuthSSLProtocolSocketFactory,其中AuthSSLProtocolSocketFactory就是定制双向认证的实例,看了前面的知识介绍理解这些实例代码就轻松了。定制这块还是很灵活的,甚至可定制SSLContext对象,即用其他第三方SSL协议实现。

4、参考资料

1、HTTP权威指南

2、https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/

JSSERefGuide.html

3、http://hc.apache.org/httpclient-3.x/sslguide.html

4、https://alvinalexander.com/java/jwarehouse/commons-httpclient-2.0.1/src/contrib/org/apache/commons/httpclient/contrib/ssl/index.shtml

相关文章

网友评论

    本文标题:HttpClient之Https请求

    本文链接:https://www.haomeiwen.com/subject/pjspqftx.html