欢迎转载,转载请标明出处:
http://blog.csdn.net/johnny901114/article/details/54754921
本文出自:【余志强的博客】
HTTP是明文请求的,它的域名、路径和参数都被中间人看得一清二楚。Google鼓励所有的网站都要使用Https,AppStore也要求新的app也要是https协议,随着各大巨头对网络安全的重视,对用户隐私的重视,是时候系统的研究下Https了。
以前在开发App的时候,在App里面内嵌H5界面,我们这个H5是http协议的,不是https的。每次开打这个H5界面总是在界面底部有小广告条,被流氓的运营商插入了他们家的广告。浏览器和安全软件也可能监听用户搜索在结果页植入广告,所以使用HTTPS愈加显得重要。
一、Https初体验
例如我们打开Chrome浏览器,输入网址 https://github.com 如下图所示:
可以看到网址
左侧有个像锁
一样的图标。Google Chrome浏览器认为这是一个安全的网站,可以有效的保护用户的隐私。
要想很好的理解Https,那我们起码要搭建一个服务器,然后然后在浏览器访问它,就像访问github一样,Google Chrome浏览器也出现一个锁图标。
接下来我们在本地搭建一个Tomcat Web容器,搭建很简单,首先下载一个Tomcat,我下载的是Tomcat7.0.73 然后解压,在conf文件夹里找到server.xml文件并打开,把下面这段代码注释打开:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
然后我们启动Tomcat发现报错了:
严重: Failed to initialize end point associated with ProtocolHandler ["http-bio-
8443"]
java.io.IOException: Keystore was tampered with, or password was incorrect
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:780)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:5
6)
at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.
java:225)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeySt
ore.java:70)
at java.security.KeyStore.load(KeyStore.java:1445)
说keystore被篡改或者密码不正确,但是我们并没有设置Keystore,说明我们缺少这个玩意。它要什么我就给它什么嘛。接下来就使用Java工具生成一个keystore,流程如下:
C:\Users\johnny>keytool -genkey -alias tomcat -keyalg RSA
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]: yu
您的组织单位名称是什么?
[Unknown]: chiclaim
您的组织名称是什么?
[Unknown]: chiclaim
您所在的城市或区域名称是什么?
[Unknown]: hangzhou
您所在的省/市/自治区名称是什么?
[Unknown]: zhejiang
该单位的双字母国家/地区代码是什么?
[Unknown]: cn
CN=yu, OU=chiclaim, O=chiclaim, L=hangzhou, ST=zhejiang, C=cn是否正确?
[否]: y
输入 <tomcat> 的密钥口令
(如果和密钥库口令相同, 按回车):
密码我设置为 123456
。在C盘用户目录下就有一个.keystore
文件,在Tomcat目录下新建一个keystore文件夹,将文件拷贝到该目录下,然后修改server.xml中我们取消注释的那段配置加两个属性keystoreFile
,keystorePass
。keystoreFile代表我们刚才生成keystore文件路径,keystorePass就是我们生成时设置的密码:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="keystore/.keystore" keystorePass="123456"
clientAuth="false" sslProtocol="TLS" />
然后往浏览器框里输入:https://localhost:8443/
结果如下所示:
点击高级
然后点击继续前往localhost(不安全)
然后就会出现成功界面:
我们发现,网址左侧的带锁的图标被打了一个叉,而且https
也被划了一条斜线。
那么接下来就需要探讨下Https的证书了
二、Https证书(Certificate)
为什么需要证书
假如我们要去买一颗价值不菲的钻石,那么我们肯定很关心我们想买的钻石的真伪,但是我们对甄别钻石的真伪不是很在行,那么我们怎么办?其实每颗钻石都有一个证书,这个证书就是为了证明钻石的真伪的。那么第一个问题来了,我们怎么知道这个钻石的证书不是伪造的呢?每个证书都是由机构颁发的。那第二个问题来了,我怎么知道这个机构是不是权威的机构呢?而且第二个问题整个问题的关键所在。因为如果机构有问题,那么下面的所有的东西都可能是假的。要想得到客户的信任,那么这个机构肯定是得到业界的认可。(关于钻石的比喻来自网上,为了更好的理解做了部分修改,点击查看原文)
在Https验证证书也是这样的,怎么验证证书是合法的,首先证书是由受信任的数字证书颁发机构CA[Certificate Authority]
颁发的,为什么要说是受信任
的呢?并不是所有CA机构签发的SSL证书都受浏览器信任,不受浏览器信任的SSL证书会报错该证书不受信任
。如果该CA机构被WebTrust
机构认证,那么该CA机构是被信任的。那么什么是WebTrust
认证呢?
什么是WebTrust
认证
Webtrust
认证是电子认证服务行业唯一的国际性认证标准。
起步于1998年初,由美国注册会计师协会(AICPA)、加拿大注册会计师协会(CICA)联合设立。
作为一项规范CA机构运营服务的国际标准,Webtrust
认证得到了国际上大多数CA
的认可,成为微软等大厂商支持的标准,目前Verisign
、Entrust
、Identrust
等国际上的大型CA机构以及发达国家和地区的认证机构大多数都获得了Webtrust
认证。
香港、台湾、澳门等也各有一家CA获得了这一认证。
通过认证后,意味着CA机构的运营管理和服务水平符合国际标准,并且有能力、有资质提供全球化认证服务,是可靠电子认证服务的有效证明。
主流的浏览器厂商,例如微软IE浏览器、 Mozilla火狐浏览器、苹果Safari浏览器以及谷歌Chrome浏览器在根证书植入项目中,一个基本
的要求就是要通过Webtrust
认证,实现浏览器与数字证书的无缝嵌入。
关于上面WebTrust
的科普来自此处
证书链和根证书
有时一个被信任的证书机构可能授权另一个证书机构颁发证书,也就是说会出现多个认证层级,这样就出现了证书链。如下图所示:
上图的证书C
就是根证书。除了根证书,其它证书都要依靠上一级的证书,来证明自己。
根证书是一份特殊的证书,它的签发者是它本身,下载根证书就表明您对该根证书以下所签发的证书都表示信任,而技术上则是建立起一个验证证书信息的链条,证书的验证追溯至根证书即为结束。所以说用户在使用某个数字证书之前必须先下载其根证书。
证书有多种格式
X.509 证书通常用于包含一个公钥
PKCS12 证书通常用来包含一个私钥,PKCS12需要密码才能打开。
创建和导入自签名证书
在上面的Https初体验
中我们知道,当输入https://localhost:8443/
后,Chrome浏览器会提示 您的连接不是私密连接
,为什么呢?
通过上面对证书
的介绍,我想大家应该已经明白了,因为证书是我们自己签名的,并不是权威机构发布的。所以我们访问https://github.com
的时候,显示安全的,但是访问https://localhost:8443/
会出现安全提示。
那有什么办法访问https://localhost:8443/
像访问github那样直接显示安全呢?如果明白了证书的原理,这也是很简单的,我们访问https://github.com
的时候显示安全,是因为Chrome浏览器内置了许多根证书,也就是说信任了这些根证书,我们只需要让系统信任我们自己的根证书就可以实现这样的需求了。
下面来生成一个证书:
1)生成一个别名为tomcat的keystore
keytool -genkey -alias tomcat -keyalg RSA
需要注意的是,注意把您的名字与姓氏是什么?
设置为你的本地IP
2)对刚才生成的keystore自签名一下
keytool -selfcert -alias tomcat -keystore C:/Users/johnny/.keystore
3)导出证书
keytool -export -alias tomcat -keystore C:/Users/johnny/.keystore -storepass 123456 -rfc -file C:/Users/johnny/tomcat.cer
主要就是三个步骤,具体的细节,可以参考我下面的记录。
下面是在我计算机上的生成证书的完整记录:
C:\Users\johnny>keytool -genkey -alias tomcat -keyalg RSA
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]: 192.168.0.103
您的组织单位名称是什么?
[Unknown]: Chiclaim
您的组织名称是什么?
[Unknown]: Chiclaim
您所在的城市或区域名称是什么?
[Unknown]: Hangzhou
您所在的省/市/自治区名称是什么?
[Unknown]: Zhejiang
该单位的双字母国家/地区代码是什么?
[Unknown]: cn
CN=192.168.0.103, OU=Chiclaim, O=Chiclaim, L=Hangzhou, ST=Zhejiang, C=cn是否正确
?
[否]: y
输入 <tomcat> 的密钥口令
(如果和密钥库口令相同, 按回车):
C:\Users\johnny>keytool -selfcert -alias tomcat -keystore C:/Users/johnny/.keyst
ore
输入密钥库口令:
C:\Users\johnny>keytool -export -alias tomcat -keystore C:/Users/johnny/.keystor
e -storepass 123456 -rfc -file C:/Users/johnny/tomcat.cer
存储在文件 <C:/Users/johnny/tomcat.cer> 中的证书
在用户目录生成了两个文件(.keystore
和tomcat.cer
):
接下来就是要让系统信任我们的证书了(我用的是Chrome浏览器,当然也可以使用IE):
1)打开Google Chrome浏览器设置界面,滑倒最底部:
2)点击 管理证书
3)点击受信任的根证书颁发机构
后面就是傻瓜式的下一步了,最后系统可能会弹出一个警告,直接确定就可以了。
我们操作的其实是系统的信任的证书,虽然我们设置了Chrome浏览器,在IE也是生效的。我们在Windows命令框里输入 certmgr.msc
,可以看到我们刚刚设置的受信任的根证书
:
最后,我们看看浏览器访问的结果,记得输入的不是localhost,而是你本地的IP:
Chrome浏览器:
IE浏览器:
至此,我们在宏观上对证书有了一个比较全面的了解。当我们访问 https://192.168.0.103:8443 的时候,浏览器又是怎么对证书进行校验的呢?
客户端验证证书
浏览器校验证书的时候,主要校验以下条件:
1)证书被系统的某个根证书信任
为什么证书要被系统某个根证书信任呢?就是为了判断用户访问的服务器端的证书是否是权威机构签发的。
当然,如果用户自己导入第三方根证书,那说明用户信任该证书,这就另当别论了。就像上面我们把自定义的根证书导入到了系统,让浏览器信任。
2)证书上绑定的域名和该网站的域名一致
我们在生成证书的时候,把您的名字与姓氏是什么?
设置为你的本地IP(192.168.0.103)
证书上绑定的域名和该网站的域名一致。所以我们访问的时候是没有问题的。
假如我们在生成证书的时候绑定的不是本地IP(192.168.0.103),那么会怎么样?我们现在重新生成一个证书吧,把IP设置为192.168.0.104,然后导入根证书,然后访问 https://192.168.0.103:8443/
:
Chrome浏览器的错误提醒:
IE浏览器错误提醒:
如果不使用Https,用户访问服务器,可能会被第三方拦截,如下图所示:
从上面的证书域名绑定的问题可以看出,Https可以有效的避免客户端(Client)和服务器端(Server)之间通信被其他人第三方截获。因为我们在通信的过程中能确保对方是合法的服务提供商。但是能确保对方的合法身份还是不够,还要确保在交互的过程中发送的数据是加密的,只有彼此才能解密,这样才能最终保证安全,关于Https
加密
与解密
后面会介绍。
3)证书没有过期
但是上面我们生成证书的时候并没有设置证书的有效期,那么证书的有效期是多久?
证书是1月24日生成的,到4月24日过期,所以证书的默认有效期为三个月
如果证书过期,IE浏览器会提示证书错误
:
当然,生成证书的时候也可以指定有效期,通过 -validity
参数,如 -validity 365 有效期365天。
向读者提出的问题
写到这里,对证书这块有了一个非常全面的了解了,最后向读者提一个问题,如果这篇文章真的理解了,这个问题很好解答。
问题描述如下:当我们访问12306的时候,如:https://www.12306.cn/mormhweb/ 结果如下:
问题1:为什么浏览器会在网址左侧的https上打了斜线(红叉)?
问题2:为什么12306界面里提示用户要安装根证书?
三、加密技术
为了更好的理解Https,先要来了解下加密技术。主要包括 对称加密
和 非对称加密
。
对称加密
对称加密采用了对称密码编码技术,它的特点是对内容使用相同的密钥来加密或者解密,即加密密钥
也可以用作解密密钥
,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难。
常用的对称加密算法有DES、DESede、IDEA、AES、Blowfish等等。
DES算法密钥偏短(56位),受到诸如查分密码分析和线性密码分析等各种攻击威胁,安全性受到严重威胁。DES算法的半公开性,该算法被广大密码学机构质疑。1998年后,实用化DES算法破译机的出现,DES算法已经不具备安全性。
然后DESede算法出现了,在一定程度上提升了算法安全强度,由于DESede算法的低效加密实现和较慢速度仍然不能满足我们对安全的要求。AES算法正是基于这些原因而诞生了。AES算法因密钥建立时间短、灵敏性好、内存要求低等优点,AES算法成为DES算法的替代者。
非对称加密
非对称加密算法有别于对称加密算法,将密钥一分为二,公钥
公开,私钥
保密。公钥通过非安全通道发放,私钥则由发放者保留。公钥于私钥相对应,成对出现。公钥加密的数据,只能使用私钥对其解密。反之,私钥加密数据,公钥对其解密。
非对称加密算法和对称加密算法相比,密钥管理问题不复存在,在安全性上有着无法逾越的高度,但是无法避免加密/解密效率低
这一问题。因此,非对称加密算法往往应用在一些安全性要求相当高的领域,如B2B、B2C等电子商务平台。
针对非对称加密算法的效率低问题,各密码学机构主张将对称加密算法与非对称加密算法相结合,使用对称加密算法
为数据加密/解密,使用非对称加密算法
的公钥
和私钥
为对称加密算法的密钥
加密/解密。利用对称加密算法的高效性,加之非对称加密算法的密钥管理,提升整体加密系统的安全性。
在算法设计上,非对称加密算法对加密数据长度有着极为苛刻的要求。例如,RSA算法要求待加密数据不得大于53个字节。
非对称加密算法主要用于交换对称加密算法的秘密密钥,而非数据交换。
常见的非对称加密算法有:RSA、ECC、Diffie-Hellman、El Gamal、DSA(数字签名用)
上面对对称加密算法
和非对称加密算法
的介绍主要来自《Java加密与解密的艺术》,这本书对加密与解密有着详细、系统的介绍,有兴趣的读者可以去看看。
四、Https的交互过程
关于Https的交互过程,下面一张图非常清楚的描述了该过程:
下面对流程图用文字的形式解释一遍:
1)客户端发起一个https的请求,把自身支持的一系列Cipher Suite(密钥算法套件,简称Cipher)发送给服务端
2)服务端接收到客户端所有的Cipher后与自身支持的对比,如果不支持则连接断开,反之则会从中选出一种加密算法和HASH算法,以证书的形式返回给客户端。
3)客户端收到服务端响应的证书后
第一步、校验证书的是否有效。关于客户端校验证书的是否有效已经做了详细的介绍,这里就不赘述了。
第二步、生成随机密码。如果证书验证通过,或者用户接受了不授信的证书,此时浏览器会生成一串随机密码,然后用证书中的公钥加密。
第三步、用最开始约定好的HASH方式,把握手消息取HASH值,把用 `随机数密码`加密 “握手消息+握手消息HASH值(签名)”和用公钥加密的随机密码 一起发送给服务端。
把握手消息做一个签名,用于验证握手消息在传输过程中没有被篡改过。
4)服务端拿到客户端传来的密文,用自己的私钥来解密,获取随机密码,再用随机数密码 解密 握手消息与HASH值,并与传过来的HASH值做对比确认是否一致。然后用随机密码加密一段握手消息(握手消息+握手消息的HASH值 )给客户端。(此时服务器端已经获取到了客户端生成的随机密码
了)
5)客户端用随机密码解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束。
之后所有的通信数据将由之前浏览器生成的随机密码
作为对称加密算法
的密钥对数据进行加密或解密。
其实上面的整个流程可以用一句话来概括:使用非对称加密算法来交换对称加密算法的密钥,使用这个对称加密算法的这个密钥来加密或解密数据。就像介绍加密这块内容的时候说的:非对称加密算法主要用于交换对称加密算法的秘密密钥,而非数据交换。
写在后面的话
写这篇博客大概花了4-5天的时间,期间断断续续的。
白天没有怎么写,主要还是晚上在写,在写的过程中也是在不断的学习。
以前对Https也是似懂非懂的感觉。现在发现通过博客的形式来推动技术的研究也是挺好的,我是边研究边写的,查阅了很多资料。阅读了一些资料,然后不断地自己给自己提出问题,然后自己找资料来解答自己的疑问。
随着自己提出的问题越多,解决的越多,那么你对该技术的理解也就越深入。
所以在研究技术的时候要不断的给自己提出问题,而不是看了几篇博客就感觉自己懂了。有句话老话说得好,检验这门技术是否真正的掌握,是去教别人,然后解决他的一些提问。
在一个就是多动手,俗话说纸上得来终觉浅嘛。有的时候别人说的不一定正确,只有自己试过才知道。
最后一句话:多归纳,多总结,多提问,多动手!