java 实现https请求的基本原理与介绍(2)SSL篇和证书盘点和HttpsURLConnection的使用

如图为JSSE接
口的主要类图:

 

①  通信核心类——SSLSocket和SSLServerSocket。对于使用过socket进行通信开发的朋友比较好理解,它们对应的就是Socket与ServerSocket,只是表示实现了SSL协议的Socket和ServerSocket,同时它们也是Socket与ServerSocket的子类。SSLSocket负责的事情包括设置加密套件、管理SSL会话、处理握手结束时间、设置客户端模式或服务器模式。

②  客户端与服务器端Socket工厂——SSLSocketFactory和SSLServerSocketFactory。在设计模式中工厂模式是专门用于生产出需要的实例,这里也是把SSLSocket、SSLServerSocket对象创建的工作交给这两个工厂类。

③  SSL会话——SSLSession。安全通信握手过程需要一个会话,为了提高通信的效率,SSL协议允许多个SSLSocket共享同一个SSL会话,在同一个会话中,只有第一个打开的SSLSocket需要进行SSL握手,负责生成密钥及交换密钥,其余SSLSocket都共享密钥信息。

④  SSL上下文——SSLContext。它是对整个SSL/TLS协议的封装,表示了安全套接字协议的实现。主要负责设置安全通信过程中的各种信息,例如跟证书相关的信息。并且负责构建SSLSocketFactory、SSLServerSocketFactory和SSLEngine等工厂类。

⑤  SSL非阻塞引擎——SSLEngine。假如你要进行NIO通信,那么将使用这个类,它让通过过程支持非阻塞的安全通信。

⑥  密钥管理器——KeyManager。此接口负责选择用于证实自己身份的安全证书,发给通信另一方。KeyManager对象由KeyManagerFactory工厂类生成。

⑦  信任管理器——TrustManager。此接口负责判断决定是否信任对方的安全证书,TrustManager对象由TrustManagerFactory工厂类生成。

(8)X590TrustedManager: TrustManager的子接口,管理X509证书,验证远程安全套接字

 

 

new java.security.SecureRandom() 相比Random 是更可靠真实的随机数

SSLContext.getProtocol(): 返回当前SSLContext对象的协议名称

SSLContext.init():  初始化当前SSLContext对象。 三个参数均可以为null。 详见JDK文档。

SSLEngine.getSupportedProtocols()等几个方法可以返回些 Engine上支持/已启用的协议、支持/已启用的加密套件

 

 

由于https涉及到证书的认证方式,这里简单介绍一下: 
关于证书,可以简单把它理解为网站的身份证。而给网站颁发身份证的就是CA(证书颁发机构)。 
可以颁发证书的CA有很多(国内外都有),只有少数CA被认为是权威、公正的,这些CA颁发的证书,浏览器、操作系统才认为是信得过的。 
在Android系统中,就有一个根证书信任列表,若我们的证书是由这个列表中的某个根证书的子证书,就不需要在https使用过程中特别指定了。 
我们自己也可以自己制作证书,例如使用OpenSSL就可以生成一个CA根证书,然后用这个根证书颁发两个子证书server和client,server证书放在服务器端,而这个client证书就可以用于浏览器或者安卓app中。这种自己制作的证书,就必须在app中指定了,否则https握手是不能成功的。 
我就按使用证书的不同方式来进行分别说明:

1,信任系统提供的证书(权威CA颁发); 
2,全部信任证书; 
3,信任指定证书;

HttpURLConnection

 

任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。

虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStream或OutputStream的close()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket。

  1. // 设定请求的方法为"POST",默认是GET    
  2. httpUrlConnection.setRequestMethod("POST");    
  3.     
  4. // 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在    
  5. // http正文内,因此需要设为true, 默认情况下是false;    
  6. httpUrlConnection.setDoOutput(true);    
  7.      
  8. // 设置是否从httpUrlConnection读入,默认情况下是true;    
  9. httpUrlConnection.setDoInput(true);    
  10.      
  11. // Post 请求不能使用缓存    
  12. httpUrlConnection.setUseCaches(false);    
  13.      

   HttpURLConnection连接问题: //在getOutputStream/getInputStream会隐含的进行connect(即:如同调用上面的connect()方法, 

// 所以在开发中不调用上述的connect()也可以)。 
OutputStream outStrm = httpUrlConnection.getOutputStream(); 
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
posted @ 2017-11-20 15:06  码农Ne'w出新世界  阅读(1521)  评论(0编辑  收藏  举报