一、背景
成都创新互联专注于企业全网整合营销推广、网站重做改版、滦平网站定制设计、自适应品牌网站建设、H5响应式网站、商城开发、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为滦平等各大城市提供网站开发制作服务。HTTP是一个传输内容有可读性的公开协议,客户端与服务器端的数据完全通过明文传输。在这个背景之下,整个依赖于Http协议的互联网数据都是透明的,这带来了很大的数据安全隐患。想要解决这个问题有两个思路:
第一种在现实中的应用范围其实比想象中的要广泛一些。双方线下交换密钥,客户端在发送的数据采用的已经是密文了,这个密文通过透明的Http协议在互联网上传输。服务端在接收到请求后,按照约定的方式解密获得明文。这种内容就算被劫持了也不要紧,因为第三方不知道他们的加解密方法。然而这种做法太特殊了,客户端与服务端都需要关心这个加解密特殊逻辑。
第二种C/S端可以不关心上面的特殊逻辑,他们认为发送与接收的都是明文,因为加解密这一部分已经被协议本身处理掉了。
从结果上看这两种方案似乎没有什么区别,但是从软件工程师的角度看区别非常巨大。因为第一种需要业务系统自己开发响应的加解密功能,并且线下要交互密钥,第二种没有开发量。
HTTPS是当前最流行的HTTP的安全形式,由NetScape公司首创。在HTTPS中,URL都是以https://开头,而不是http://。使用了HTTPS时,所有的HTTP的请求与响应在发送到网络上之前都进行了加密,这是通过在SSL层实现的。
二、加密方法
通过SSL层对明文数据进行加密,然后放到互联网上传输,这解决了HTTP协议原本的数据安全性问题。一般来说,对数据加密的方法分为对称加密与非对称加密。
2.1 对称加密
对称加密是指加密与解密使用同样的密钥,常见的算法有DES与AES等,算法时间与密钥长度相关。
对称密钥大的缺点是需要维护大量的对称密钥,并且需要线下交换。加入一个网络中有n个实体,则需要n(n-1)个密钥。
2.2 非对称加密
非对称加密是指基于公私钥(public/private key)的加密方法,常见算法有RSA,一般而言加密速度慢于对称加密。
对称加密比非对称加密多了一个步骤,即要获得服务端公钥,而不是各自维护的密钥。
整个加密算法建立在一定的数论基础上运算,达到的效果是,加密结果不可逆。即只有通过私钥(private key)才能解密得到经由公钥(public key)加密的密文。
在这种算法下,整个网络中的密钥数量大大降低,每个人只需要维护一对公司钥即可。即n个实体的网络中,密钥个数是2n。
其缺点是运行速度慢。
2.3 混合加密
周星驰电影《食神》中有一个场景,黑社会火并,争论撒尿虾与牛丸的底盘划分问题。食神说:“真是麻烦,掺在一起做成撒尿牛丸那,笨蛋!”
对称加密的优点是速度快,缺点是需要交换密钥。非对称加密的优点是不需要交互密钥,缺点是速度慢。干脆掺在一起用好了。
混合加密正是HTTPS协议使用的加密方式。先通过非对称加密交换对称密钥,后通过对称密钥进行数据传输。
由于数据传输的量远远大于建立连接初期交换密钥时使用非对称加密的数据量,所以非对称加密带来的性能影响基本可以忽略,同时又提高了效率。
三、HTTPS握手
可以看到,在原HTTP协议的基础上,HTTPS加入了安全层处理:
四、HttpClient对HTTPS协议的支持
4.1 获得SSL连接工厂以及域名校验器
作为一名软件工程师,我们关心的是“HTTPS协议”在代码上是怎么实现的呢?探索HttpClient源码的奥秘,一切都要从HttpClientBuilder开始。
public CloseableHttpClient build() { //省略部分代码 HttpClientConnectionManager connManagerCopy = this.connManager; //如果指定了连接池管理器则使用指定的,否则新建一个默认的 if (connManagerCopy == null) { LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory; if (sslSocketFactoryCopy == null) { //如果开启了使用环境变量,https版本与密码控件从环境变量中读取 final String[] supportedProtocols = systemProperties ? split( System.getProperty("https.protocols")) : null; final String[] supportedCipherSuites = systemProperties ? split( System.getProperty("https.cipherSuites")) : null; //如果没有指定,使用默认的域名验证器,会根据ssl会话中服务端返回的证书来验证与域名是否匹配 HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier; if (hostnameVerifierCopy == null) { hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy); } //如果制定了SslContext则生成定制的SSL连接工厂,否则使用默认的连接工厂 if (sslContext != null) { sslSocketFactoryCopy = new SSLConnectionSocketFactory( sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy); } else { if (systemProperties) { sslSocketFactoryCopy = new SSLConnectionSocketFactory( (SSLSocketFactory) SSLSocketFactory.getDefault(), supportedProtocols, supportedCipherSuites, hostnameVerifierCopy); } else { sslSocketFactoryCopy = new SSLConnectionSocketFactory( SSLContexts.createDefault(), hostnameVerifierCopy); } } } //将Ssl连接工厂注册到连接池管理器中,当需要产生Https连接的时候,会根据上面的SSL连接工厂生产SSL连接 @SuppressWarnings("resource") final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager( RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactoryCopy) .build(), null, null, dnsResolver, connTimeToLive, connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS); //省略部分代码 } }