参考文章:
- 彻底搞懂HTTPS的加密原理 (opens new window)
- HTTPS协议是如何保证安全的 (opens new window)
- HTTPS协议是如何保证安全的 (opens new window)
- 公钥信任问题 — 数字证书与 CA (opens new window)
- HTTPS 加密了什么内容? (opens new window)
# 为什么需要加密传输
常规的HTTP通信,有以下的问题。
- 窃听风险(eavesdropping):第三方可以获知通信内容。
- 篡改风险(tampering):第三方可以修改通信内容。
- 冒充风险(pretending):第三方可以冒充他人身份参与通信。
因此,为了解决这三大风险,SSL/TLS协议应运而生,希望达到:
- 所有信息都是加密传播,第三方无法窃听。
- 具有校验机制,一旦被篡改,通信双方会立刻发现。
- 配备身份证书,防止身份被冒充。
HTTPS是经由HTTP进行通信,但利用SSL/TLS来加密数据包。
- SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。
- TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。TLS以SSL3.0为基础于1999年作为SSL的新版本推出。
TIPS
安全套接层 (SSL) (opens new window)是一种协议,支持服务通过网络进行通信而不损害安全性。它在客户端和服务器之间创建一个安全连接。然后通过该连接安全地发送任意数据量。
安全套接字层是用于服务器之上的一个加密系统,它可以确保在客户机与服务器之间传输的数据仍然是安全与隐密的。要使服务器和客户机使用SSL进行安全的通信,服务器必须有两样东西:
- 密钥对(Key pair) —— 一个密钥对包括一个公钥和一个私钥。这两个密钥用来对消息进行加密和解密,以确保在因特网上传输时的隐密性和机密性。
- 证书(Certificate) —— 证书用来进行身份验证或者身份确认。证书可以是自签(self-signed)证书,也可以是颁发(issued)证书。自签证书是为自己私有的Web网络创建的证书。颁发证书是认证中心(certificate authority,CA)或者证书签署者提供(颁发)给您的证书。
SSL/TLS协议的基本思路是采用公钥加密法,也就是非对称加密。
- 对称加密:加密和解密使用同一个密钥。加解密效率比非对称加密高。但是密钥一旦泄露,通信就不安全了。
- 非对称加密:存在密钥对,公钥加密私钥解密或者私钥加密公钥解密,无法通过公钥反推私钥,也无法通过私钥反推公钥。
# 为什么需要同时使用对称加密和非对称加密
- 如果只使用对称加密:任何一方密钥泄露,就不能安全通信。
- 使用一对密钥的非对称加密:服务端通过明文传输公钥给客户端,客户端通过公钥加密数据传输到服务端,服务端私钥解密,保证客户端到服务端传输数据的安全性,但是不能保证服务端到客户端传输数据的安全性,因为明文传输公钥有可能被劫持。
- 使用两对密钥的非对称加密:服务端和客户端分别通过明文把公钥传给对方,双方传输数据都通过公钥加密,私钥解密,看似能完美解决问题,但是很重要的原因是非对称加密算法非常耗时,而对称加密快很多。
# 对称加密+非对称加密
- 某网站拥有用于非对称加密的公钥A、私钥A’;
- 浏览器向网站服务器请求,服务器把公钥A明文给传输浏览器;
- 浏览器随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务器;
- 服务器拿到后用私钥A’解密得到密钥X;
- 这样双方就都拥有密钥X了,且别人无法知道它。之后双方所有数据都通过密钥X进行对称加密解密即可。
但是这样还是有个问题,中间人攻击:
- 某网站拥有用于非对称加密的公钥A、私钥A’;
- 浏览器向网站服务器请求,服务器把公钥A明文给传输浏览器;
- 中间人劫持到公钥A,保存下来,把数据包中的公钥A替换成自己伪造的公钥B(它当然也拥有公钥B对应的私钥B’);
- 浏览器生成一个用于对称加密的密钥X,用公钥B(浏览器无法得知公钥被替换了)加密后传给服务器;
- 中间人劫持后用私钥B’解密得到密钥X,再用公钥A加密后传给服务器;
- 服务器拿到后用私钥A’解密得到密钥X。
根本原因是浏览器无法确认收到的公钥是不是网站自己的,因为公钥本身是明文传输的,难道还得对公钥的传输进行加密?这似乎变成鸡生蛋、蛋生鸡的死循环了。
此时就需要一个权威的第三方 —— CA(Certificate Authority,证书认证机构),例如:DigiCert (opens new window)、VeriSign (opens new window)、Entrust (opens new window)、Let`s Encrypt (opens new window)、GlobalSign (opens new window)
# CA和数字证书
网站在使用HTTPS前,需要向CA申领一份数字证书。服务器把证书传输给浏览器,浏览器从证书里获取公钥就行了,证书就如身份证,证明“该公钥对应该网站”。
# 证书体系
“小一点”的CA可以让“大CA”签名认证,但链条的最后,也就是Root CA,就只能自己证明自己了,这个就叫“自签名证书”(Self-Signed Certificate)或者“根证书”(Root Certificate)。对于根证书我们必须无条件相信,否则整个证书信任链就走不下去了。有了这个证书体系,操作系统和浏览器都内置了各大CA的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层地验证,直到找到根证书,就能够确定证书是可信的,从而里面的公钥也是可信的。
数字证书主要包括以下内容:
- 证书颁发机构的名称。
- 证书持有者信息。
- 证书持有者公钥。
- 证书签名用到的Hash算法。
- 有效期等等其他信息。
而这里又有一个显而易见的问题,“证书本身的传输过程中,如何防止被篡改”?即如何证明证书本身的真实性?身份证运用了一些防伪技术,而数字证书怎么防伪呢?
# 如何放防止数字证书被篡改
我们把证书原本的内容生成一份“签名”,比对证书内容和签名是否一致就能判别是否被篡改。这就是数字证书的“防伪技术”,这里的“签名”就叫数字签名。
数字签名的制作过程:
- CA拥有非对称加密的私钥和公钥;
- CA对证书明文数据T进行hash;
- 对hash后的值用私钥加密,得到数字签名S。
明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了。
那浏览器拿到服务器传来的数字证书后,如何验证它是不是真的(有没有被篡改、掉包)?浏览器验证过程:
- 拿到证书,得到明文T,签名S;
- 用CA的公钥对S解密(由于是浏览器信任的机构,所以浏览器保有它的公钥),得到S’;
- 用证书里指明的hash算法对明文T进行hash得到T’。
显然通过以上步骤,T’应当等于S’,除非明文或签名被篡改。所以此时比较S’是否等于T’,等于则表明证书可信。
中间人有可能篡改该证书吗?
假设中间人篡改了证书的原文,由于他没有CA的私钥,所以无法得到此时加密后签名,就无法相应地篡改签名。浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。
那中间人有可能把证书掉包吗?
假设有另一个网站B也拿到了CA认证的证书,它想劫持网站A的信息。于是它成为中间人拦截到了A传给浏览器的证书,然后替换成自己的证书,传给浏览器,之后浏览器就会错误地拿到B的证书里的公钥了,这确实会导致“中间人攻击”的漏洞?其实这并不会发生,因为证书里包含了网站A的信息,包括域名,浏览器把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。
那第三方攻击者能否让自己的证书显示出来的信息也是服务端呢?(伪装服务端一样的配置)
显然这个是不行的,因为当第三方攻击者去CA那边寻求认证的时候,CA会要求其提供例如域名的whois (opens new window)信息、域名管理邮箱等证明你是服务端域名的拥有者,而第三方攻击者是无法提供这些信息所以他就是无法骗CA他拥有属于服务端的域名。
中间人也能正常获取网站公钥
的确,中间人自己通过浏览器访问网站时也能得到公钥,这个公钥跟正常用户的公钥是一致的。但是每个客户端和服务器通信使用的对称密钥都是临时生成且随机的,中间人只能知道自己的随机密钥,但是不知道其他的随机密钥。
为什么制作数字签名时需要hash一次?
似乎那里的hash有点多余,把hash过程去掉也能保证证书没有被篡改。最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加解密就快很多。(非对称算法RSA只能加密比私钥小11个字节的数据)。
每次进行HTTPS请求时都必须在SSL/TLS层进行握手传输密钥吗?
服务器会为每个浏览器(或客户端软件)维护一个session id,在TLS握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session id下,之后浏览器每次请求都会携带session id,服务器会根据session id找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了。
# 怎么证明CA的公钥是可信的
数字证书到底是干啥的?没错,为了证明某公钥是可信的,即“该公钥是否对应该网站”,那CA的公钥是否也可以用数字证书来证明?没错,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中会有CA的根证书,这样就可以拿到它对应的可信公钥了。
数字证书的实质是证书权威机构(CA)用自己的私钥,对普通用户提交的公钥和名称的绑定关系的数字签名。
实际上证书之间的认证也可以不止一层,可以A信任B,B信任C,以此类推,我们把它叫做信任链或数字证书链。也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。
# 假设CA出错或不可信
CRL (opens new window)和OCSP (opens new window)
如果CA失误或者被欺骗,签发了错误的证书,虽然证书是真的,可它代表的网站确实假的。针对这种情况开发出了CRL(证书吊销列表,Certificate revocation list)和OCSP(在线证书状态协议,Online Certificate Status Protocol),两种协议用于及时废止有问题的证书。
黑名单
如果CA被黑客攻陷,或者CA有恶意,因为它(即根证书)是信任的源头,整个信任链里的所有证书也就都不可信了。该种场景因为涉及的证书太多,就只能操作系统或者浏览器从根上“下狠手”了,撤销对CA的信任,列入“黑名单”,这样它颁发的所有证书就都会被认为是不安全的。
# HTTPS中间人攻击
HTTPS从协议上解决了HTTP时代的中间人攻击问题,但是HTTPS在用户主动信任了伪造证书的时候也会发生中间人攻击(比如早期的12306需要手动信任证书),HTTPS中间人攻击流程如下:
- 客户端用HTTPS连接服务器的443端口;
- 服务器下发自己的数字证书给客户端;
- 黑客劫持了服务器的真实证书,并伪造了一个假的证书给浏览器;
- 浏览器可以发现得到的网站证书是假的,但是浏览器选择信任;
- 浏览器生成随机对称密钥A,用伪造的证书中的公钥加密发往服务器;
- 黑客同样可以劫持这个请求,得到浏览器的对称密钥A,从而能够窃听或者篡改通信数据;
- 黑客利用服务器的真实公钥将客户端的对称密钥A加密发往服务器;
- 服务器利用私钥解密这个对称密钥A之后与黑客通信;
- 黑客利用对称密钥A解密服务器的数据,篡改之后利用对称密钥A加密发给客户端;
- 客户端收到的数据已经是不安全的了。
以上就是HTTPS中间人攻击的原理,这也就是HTTPS抓包为什么要信任证书的原因。