前言
大家都知道,http和https相比,https更加安全。 为什么会更加安全呢?
- HTTP本身是明文传输的,没有经过任何安全处理。在HTTP协议下,中间者可以随意嗅探用户搜索内容,窃取隐私甚至篡改网页。
- HTTPS == HTTP+TLS/SSL,即HTTP下加入TLS/SSL层。 通常,http直接和TCP通信。使用SSL之后,就演变成先和SSL通信,再由SSL和TCP通信。 HTTPS的安全基础就是TLS/SSL。服务端和客户端的信息传输都会通过TLS/SSL进行加密,所以传输的数据都是加密之后的数据。
说到加密,我们可能会有这样的疑问:https怎么加密的?整个工作流程又是怎样的?接下来的内容回答了这俩问题哦!耐心往下看吧~
加密——解决内容可能被窃听的问题
对称加密
又叫共享密钥加密。指加密和解密使用相同密钥的加密算法。常见的对称加密算法有:DES, AES, RC4, IDEA。
单独使用对称加密,不谈浏览器和服务器是如何拥有秘钥A
的,步骤可能是这样的:
**弊端:**持有密钥才能进行加密解密,如何安全地转交?在互联网上转发密钥时,中间人也许会拿到密钥。
非对称加密
什么是非对称加密
有两把钥匙,一把公钥,一把私钥。私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。用公钥加密的内容必须用私钥才能解开,同样,私钥加密的内容只有公钥能解开。利用这种方式,不需要发送私钥,也不必担心私钥被攻击者窃听而盗走。
非对称加密的弊端
- 公钥是公开的,所以针对私钥加密的信息,黑客截获后可以使用公钥进行解密,获取其中的内容;
- 公钥并不包含服务器的信息,使用非对称加密算法无法确保服务器身份的合法性,存在中间人攻击的风险,服务器发送给客户端的公钥可能在传送过程中被中间人截获并篡改;
- 使用非对称加密在数据加密解密过程需要消耗一定时间,降低了数据传输效率;
使用非对称加密的两个方案
我们思考一下,如果我们去设计https,会使用什么方案来加密呢?也许会想到以下的两种方案:
非对称加密方案
鉴于非对称加密的机制,我们可能会有这种思路:
- 服务器先把公钥直接明文传输给浏览器;
- 浏览器向服务器传数据前都先用这个公钥加密好再传。
这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开这条数据。但是,依然存在**问题:**如何保证服务器到浏览器这条路的安全性?
改良的非对称加密方案
我们已经理解通过一组公钥私钥,已经可以保证单个方向传输的安全性,那用两组公钥私钥,是不是就能保证双向传输都安全了?请看下面的过程:
- 某网站服务器拥有用于非对称加密的
公钥A、私钥A
;浏览器拥有用于非对称加密的公钥B、私钥B
。 - 浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
- 浏览器把
公钥B
明文传输给服务器。 - 之后浏览器向服务器传输的所有东西都用公钥A加密,服务器收到后用
私钥A
解密。由于只有服务器拥有这个私钥A
可以解密,所以能保证这条数据的安全。 - 服务器向浏览器传输的所有东西都用
公钥B
加密,浏览器收到后用私钥B
解密。同上也可以保证这条数据的安全。
为什么https没有用此方案:首先,这个方案的确可以!抛开这里面仍有的漏洞不谈(中间人攻击,下文会讲),最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快很多。
对称加密+非对称加密(HTTPS使用)
非对称加密非常耗时,而对称加密快很多,所以HTTPS采用了这种方式。请看下面的过程:
- 某网站服务器拥有用于非对称加密的
公钥A
,私钥A
; - 浏览器向网站服务器发送请求;
- 服务器将
公钥A
明文传输给浏览器; - 浏览器随机生成一个用于对称加密的
密钥X
,使用公钥A
加密后传给服务器; - 服务器使用
私钥A
解密后得到密钥X
; - 这样双方都获得了
密钥X
,且别人无法知道它,之后双方所有数据都用密钥X
加密解密。
**弊端:**单纯使用对称+非对称加密依然存在漏洞:中间人攻击。 所以除了对称+非对称,https当然还使用了其他技术,下面会讲到。
中间人攻击
中间人的确无法得到浏览器生成的密钥X
,这个密钥被公钥A
加密了,只有服务器拥有的私钥A
才能解密。但是,中间人并不需要拿到私钥A
就可以干坏事了!请看:
- 某网站服务器拥有用于非对称加密的
公钥A、私钥A
; - 浏览器向服务器请求;
- 服务器把
公钥A
传给浏览器; - 中间人生成
公钥B、私钥B
。再劫持到公钥A
,保存下来,把数据包中的公钥A
替换成自己伪造的公钥B
。再传给浏览器。 - 浏览器实际接收到的只有中间人伪造的
公钥B
,它并不知道公钥被替换了。浏览器随机生成一个用于对称加密的密钥X
,使用公钥B
加密后传给服务器。 - 中间人劫持后使用
公钥B
解密后得到密钥X
,再用公钥A
加密后传给服务器。 - 服务器拿到后用
公钥A
解密得到密钥X
。
这样在浏览器服务器双方都不会发现异常的情况下,中间人得到了密钥X
。原因在于:浏览器无法确认自己收到的公钥是不是网站自己的。为了解决这个问题,就需要使用数字证书。
**
数字证书——解决通信方身份可能被伪装的问题
解决通信方身份可能被伪装的问题,归根结底,即确认公钥是否可信,或者说确认服务器端是不是中间人伪装的。 我们可以使用数字证书来证明。数字证书向CA申请,我们先来看看CA是什么。 ** CA(Certification Authority) - 数字证书认证机构。类似于现实生活中的政府部门。
CA签发数字证书
- 服务器的运营人员向第三方机构CA提交公钥、组织信息、个人信息(域名)等信息并申请认证;
- CA通过线上、线下等多种手段验证申请者提供信息的真实性,如组织是否存在、企业是否合法,是否拥有域名的所有权等;
- 如信息审核通过,CA会向申请者签发认证文件-证书。证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA的信息、有效时间、证书序列号等信息的明文,同时包含一个签名。 其中签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA的私钥对信息摘要进行加密,密文即签名;
数字证书的内容
- CA的信息
- 申请者的信息
- 证书本身的数字签名
- 证书签名用到的Hash算法
- 证书持有者公钥
- 证书的有效时间
- 证书序列号
- ……
使用数字证书后
申请好数字证书后,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”。此时,https的流程是这样的: **依然存在问题:**中间人有可能把证书篡改或者直接掉包了,所以还需要验证证书。 **思考:**数字证书中签名的作用是什么?如何防止数字证书被纂改?
数字签名——解决报文可能遭篡改问题
**解决报文可能被纂改问题,归根结底,即确认数字证书是否可信。**数字证书中的签名其实就是数字签名。这里把签名单独抽出来讲。下图是证书中签名的生成和浏览器验证证书的过程。
数字签名的生成
- CA拥有非对称加密的私钥和公钥。
- CA对证书明文信息进行hash得到消息摘到。
- 对消息摘要用私钥加密,得到数字签名。
明文和数字签名共同组成了数字证书。这样的数字证书就可以发送给网站了。
浏览器验证证书
- 浏览器拿到证书后,得到
明文T
,数字签名S
。 - 用CA机构的公钥对
S
解密(由于是浏览器信任的机构,所以浏览器保有它的公钥),得到摘要S’
。 - 用证书里说明的hash算法对
明文T
进行hash得到摘要T’
。 - 比较
S’
是否等于T
’,等于则表明证书可信。 - 除了以上步骤外,浏览器还会验证证书相关的域名信息、有效时间等信息;客户端会内置信任CA的证书信息(包含公钥),如果CA不被信任,则找不到对应 CA的证书,证书也会被判定非法。
Https工作流程:
- 客户端发起HTTPS请求: 用户在浏览器中输入一个https网址,然后连接到server的443端口。
- 服务端返回事先配置好的公钥证书;
- 客户端验证证书: 比如是否在有效期内;证书的用途是否匹配客户端请求的站点;证书有没有在CRL吊销列表里,它的上一级证书是否有效,这个过程是递归的,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书)。 如果验证通过,继续;否则,显示警告信息。
- 生成并发送加密后对称密钥:客户端使用伪随机数生成器生成加密所使用的对称密钥,用证书的公钥加密后,发送给服务器。
- 服务端获取对称密钥:服务端使用自己的私钥解密,得到对称密码。至此,服务端和客户端双方都拥有了相同的对称密钥,后续传送的数据就可以使用此对称加密了。
- 服务端使用对称密钥加密“明文内容A”,发送给客户端。
- 客户端使用对称密钥解密获得“明文内容A”。
- 客户端再次发起https请求,使用对称密钥加密请求的“明文内容B”。然后服务端使用对称密钥解密密文,得到“明文内容B”。
Q&A
中间人有可能篡改证书吗?
假设中间人纂改了证书的原文。由于他没有CA的私钥,所以他无法得到此时加密后的签名,无法相应地纂改签名。 浏览器收到证书后会发现原文hash后的值与签名解密后的hash值不一致,从而验证失败,证书不可信,便会终止向服务器传输信息,防止信息泄露给中间人。
思考:不能更改,那么把证书整个掉包呢?
中间人有可能把证书掉包吗?
假设中间人拦截到了服务器传给浏览器的证书,替换成伪造的证书后传给浏览器。之后浏览器就会错误地拿到伪造证书地公钥了。 但这并不会发生。中间人是没办法轻易伪造证书的。首先,申请证书时,中间人也必须向CA提交自己的信息,且这些信息必须真实。其次,就算中间人成功申请到了证书并替换,浏览器只需要对比信息就可以知道证书是否有效了。
为什么制作数字签名时需要hash一次?
最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加密解密就会快很多。 当然还有安全上的原因,这部分内容相对深一些,感兴趣的可以看这篇解答:crypto.stackexchange.com/a/12780
怎么证明CA机构的公钥是可信的?
你们可能会发现上文中说到CA机构的公钥,我几乎一笔带过,“浏览器保有它的公钥”,这是个什么保有法?怎么证明这个公钥是否可信?
数字证书是为了证明网站服务器的公钥是可信的,即“该公钥是否对应该网站/机构等”,那这个CA机构的公钥是不是也可以用数字证书来证明?没错,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥了。
实际上证书之间的认证也可以不止一层,可以A信任B,B信任C,以此类推,我们把它叫做信任链
或数字证书链
,也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。
另外,不知你们是否遇到过网站访问不了、提示要安装证书的情况?这里安装的就是根证书。说明浏览器不认给这个网站颁发证书的机构,那么没有该机构的根证书,你就得手动下载安装(风险自己承担XD)。安装该机构的根证书后,你就有了它的公钥,就可以用它验证服务器发来的证书是否可信了。
HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?
第一次需要。服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了!
总结
- Https使用的加密方案是:对称+非对称加密;
- Https使用数字证书,解决通信方可能被伪装的问题(其实就是防止中间人伪装成Server端);
- Https使用数字签名,解决报文可能遭篡改的问题(其实就是防止数字证书被篡改或掉包)。