HTTP 由于是明文传输,存在中间人窃取、伪造、篡改的风险

image.png
从上图可以看出,我们使用 HTTP 传输的内容很容易被中间人窃取、伪造和篡改,通常我们把这种攻击方式称为中间人攻击

具体来讲,在将 HTTP 数据提交给 TCP 层之后,数据会经过用户电脑、WiFi 路由器、运营商和目标服务器,在这中间的每个环节中,数据都有可能被窃取或篡改。比如用户电脑被黑客安装了恶意软件,那么恶意软件就能抓取和篡改所发出的 HTTP 请求的内容。或者用户一不小心连接上了 WiFi 钓鱼路由器,那么数据也都能被黑客抓取或篡改。

鉴于 HTTP 的明文传输使得传输过程毫无安全性可言,且制约了网上购物、在线转账等一系列场景应用,于是倒逼着我们要引入加密方案。从 HTTP 协议栈层面来看,我们可以在 TCP 和 HTTP 之间插入一个安全层,所有经过安全层的数据都会被加密或者解密,你可以参考下图:
image.png
从图中我们可以看出 HTTPS 并非是一个新的协议,通常 HTTP 直接和 TCP 通信,HTTPS 则先和安全层通信,然后安全层再和 TCP 层通信。也就是说 HTTPS 所有的安全核心都在安全层,它不会影响到上面的 HTTP 协议,也不会影响到下面的 TCP/IP,因此要搞清楚 HTTPS 是如何工作的,就要弄清楚安全层是怎么工作的

总的来说,安全层有两个主要的职责:对发起 HTTP 请求的数据进行加密操作和对接收到 HTTP 的内容进行解密操作。

HTTPS通信原理

对称加密:HTTPS 的最终加密形式

既然 HTTP 是明文传输的,那我们给报文加密不就行了,既然要加密,我们肯定需要通信双方协商好密钥吧,一种是通信双方使用同一把密钥,即对称加密的方式来给报文进行加解密。
image.png
如图示:使用对称加密的通信双方使用同一把密钥进行加解密。

对称加密具有加解密速度快,性能高的特点,也是 HTTPS 最终采用的加密形式,但是这里有一个关键问题,对称加密的通信双方要使用同一把密钥,这个密钥是如何协商出来的?如果通过报文的方式直接传输密钥,之后的通信其实还是在裸奔,因为这个密钥会被中间人截获甚至替换掉,这样中间人就可以用截获的密钥解密报文,甚至替换掉密钥以达到篡改报文的目的。

image.png
有人说对这个密钥加密不就完了,但对方如果要解密这个密钥还是要传加密密钥给对方,依然还是会被中间人截获的,这么看来直接传输密钥无论怎样都无法摆脱俄罗斯套娃的难题,是不可行的。
image.png

非对称加密:解决单向对称密钥的传输问题

image.png

非对称加密即加解密双方使用不同的密钥,一把作为公钥,可以公开的,一把作为私钥,不能公开,公钥加密的密文只有私钥可以解密,私钥加密的内容,也只有公钥可以解密。

注:私钥加密其实这个说法其实并不严谨,准确的说私钥加密应该叫私钥签名,因为私密加密的信息公钥是可以解密的,而公钥是公开的,任何人都可以拿到,用公钥解密叫做验签

这样的话对于 server 来说,保管好私钥,发布公钥给其他 client, 其他 client 只要把对称加密的密钥加密传给 server 即可,如此一来由于公钥加密只有私钥能解密,而私钥只有 server 有,所以能保证 client 向 server 传输是安全的,server 解密后即可拿到对称加密密钥,这样交换了密钥之后就可以用对称加密密钥通信了。
image.png
但是问题又来了, server 怎么把公钥安全地传输给 client 呢。如果直接传公钥,也会存在被中间人调包的风险。
image.png

数字证书,解决公钥传输信任问题

如何解决公钥传输问题呢,从现实生活中的场景找答案,员工入职时,企业一般会要求提供学历证明,显然不是什么阿猫阿狗的本本都可称为学历,这个学历必须由第三方权威机构(Certificate Authority,简称 CA)即教育部颁发,同理,server 也可以向 CA 申请证书,在证书中附上公钥,然后将证书传给 client,证书由站点管理者向 CA 申请,申请的时候会提交 DNS 主机名等信息,CA 会根据这些信息生成证书
image.png
这样当 client 拿到证书后,就可以获得证书上的公钥,再用此公钥加密对称加密密钥传给 server 即可,看起来确实很完美,不过在这里大家要考虑两个问题

问题一、 如何验证证书的真实性,如何防止证书被篡改

想象一下上文中我们提到的学历,企业如何认定你提供的学历证书是真是假呢,答案是用学历编号,企业拿到证书后用学历编号在学信网上一查就知道证书真伪了,学历编号其实就是我们常说的数字签名,可以防止证书造假。

回到 HTTPS 上,证书的数字签名该如何产生的呢,一图胜千言

image.png
步骤如下

1、 首先使用一些摘要算法(如 MD5)将证书明文(如证书序列号,DNS主机名等)生成摘要,然后再用第三方权威机构的私钥对生成的摘要进行加密(签名)

消息摘要是把任意长度的输入揉和而产生长度固定的伪随机输入的算法,无论输入的消息有多长,计算出来的消息摘要的长度总是固定的,一般来说,只要内容不同,产生的摘要必然不同(相同的概率可以认为接近于 0),所以可以验证内容是否被篡改了。

为啥要先生成摘要再加密呢,不能直接加密?

因为使用非对称加密是非常耗时的,如果把整个证书内容都加密生成签名的话,客户端验验签也需要把签名解密,证书明文较长,客户端验签就需要很长的时间,而用摘要的话,会把内容很长的明文压缩成小得多的定长字符串,客户端验签的话就会快得多。

2、客户端拿到证书后也用同样的摘要算法对证书明文计算摘要,两者一笔对就可以发现报文是否被篡改了,那为啥要用第三方权威机构(Certificate Authority,简称 CA)私钥对摘要加密呢,因为摘要算法是公开的,中间人可以替换掉证书明文,再根据证书上的摘要算法计算出摘要后把证书上的摘要也给替换掉!这样 client 拿到证书后计算摘要发现一样,误以为此证书是合法就中招了。所以必须要用 CA 的私钥给摘要进行加密生成签名,这样的话 client 得用 CA 的公钥来给签名解密,拿到的才是未经篡改合法的摘要(私钥签名,公钥才能解密)

server 将证书传给 client 后,client 的验签过程如下
image.png

这样的话,由于只有 CA 的公钥才能解密签名,如果客户端收到一个假的证书,使用 CA 的公钥是无法解密的,如果客户端收到了真的证书,但证书上的内容被篡改了,摘要比对不成功的话,客户端也会认定此证书非法。

细心的你一定发现了问题,CA 公钥如何安全地传输到 client ?如果还是从 server 传输到 client,依然无法解决公钥被调包的风险,实际上此公钥是存在于 CA 证书上,而此证书(也称 Root CA 证书)被操作系统信任,内置在操作系统上的,无需传输,如果用的是 Mac 的同学,可以打开 keychain 查看一下,可以看到很多内置的被信任的证书。
image.png
问题二、 如何防止证书被调包

实际上任何站点都可以向第三方权威机构申请证书,中间人也不例外。
image.png
正常站点和中间人都可以向 CA 申请证书,获得认证的证书由于都是 CA 颁发的,所以都是合法的,那么此时中间人是否可以在传输过程中将正常站点发给 client 的证书替换成自己的证书呢,如下所示
image.png
答案是不行,因为客户端除了通过验签的方式验证证书是否合法之外,还需要验证证书上的域名与自己的请求域名是否一致,中间人中途虽然可以替换自己向 CA 申请的合法证书,但此证书中的域名与 client 请求的域名不一致,client 会认定为不通过!

但是上面的证书调包给了我们一种思路,什么思路?大家想想, HTTPS 既然是加密的, charles 这些「中间人」为啥能抓到明文的包呢,其实就是用了证书调包这一手法,想想看,在用 charles 抓 HTTPS 的包之前我们先要做什么,当然是安装 charles 的证书
image.png
这个证书里有 charles 的公钥,这样的话 charles 就可以将 server 传给 client 的证书调包成自己的证书,client 拿到后就可以用你安装的 charles 证书来验签等,验证通过之后就会用 charles 证书中的公钥来加密对称密钥了,整个流程如下
image.png
由此可知,charles 这些中间人能抓取 HTTPS 包的前提是信任它们的 CA 证书,然后就可以通过替换证书的方式进行瞒天过海,所以我们千万不要随便信任第三方的证书,避免安全风险。

其它 HTTPS 相关问题

什么是双向认证

以上的讲述过程中,我们只是在 client 端验证了 server 传输证书的合法性,但 server 如何验证 client 的合法性,还是用证书,我们在网上进行转账等操作时,想想看是不是要先将银行发给我们的 U 盾插到电脑上?其实也是因为 U 盾内置了证书,通信时将证书发给 server,server 验证通过之后即可开始通信。
画外音:身份认证只是 U 盾功能的一种,还有其他功能,比如加解密都是在 U 盾中执行,保证了密钥不会出现在内存中

什么是证书信任链

前文说了,我们可以向 CA 申请证书,但全世界的顶级 CA(Root CA) 就那么几个,每天都有很多人要向它申请证书,它也忙不过来啊,怎么办呢,想想看在一个公司里如果大家都找 CEO 办事,他是不是要疯了,那他能怎么办?授权,他会把权力交给 CTO,CFO 等,这样你们只要找 CTO 之类的就行了,CTO 如果也忙不过来呢,继续往下授权啊。
image.png
同样的,既然顶级 CA 忙不过来,那它就向下一级,下下级 CA 授权即可,这样我们就只要找一级/二级/三级 CA 申请证书即可。怎么证明这些证书被 Root CA 授权过了呢,小一点的 CA 可以让大一点的 CA 来签名认证,比如一级 CA 让 Root CA 来签名认证,二级 CA 让一级 CA 来签名认证,Root CA 没有人给他签名认证,只能自己证明自己了,这个证书就叫「自签名证书」或者「根证书」,我们必须信任它,不然证书信任链是走不下去的(这个根证书前文我们提过,其实是内置在操作系统中的)
image.png
现在我们看看如果站点申请的是二级 CA 颁发的证书,client 收到之后会如何验证这个证书呢,实际上 service 传了传给二级 CA 的证书外,还会把证书信任链也一起传给客户端,这样客户端会按如下步骤进行验证:

  1. 浏览器就使用信任的根证书(根公钥)解析证书链的根证书得到一级证书的公钥+摘要验签
  2. 拿一级证书的公钥解密一级证书,拿到二级证书的公钥和摘要验签
  3. 再然后拿二级证书的公钥解密 server 传过来的二级证书,得到服务器的公钥和摘要验签,验证过程就结束了

    总结

    相信大家看完本文应该对 HTTPS 的原理有了很清楚的认识了, HTTPS 无非就是 HTTP + SSL/TLS
    image.png
    而 SSL/TLS 的功能其实本质上是如何协商出安全的对称加密密钥以利用此密钥进行后续通讯的过程,带着这个疑问相信你不难理解数字证书和数字签名这两个让人费解的含义,搞懂了这些也就明白了为啥 HTTPS 是加密的,charles 这些工具却能抓包出明文来。

什么是 HTTPS?

HTTP 存在哪些安全问题?

由于 HTTP 是明文传输,因此主要存在三种安全问题:

1、窃听风险

由于数据在传输的过程中会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果在这过程中传输的内容被劫持,则会造成窃听的问题,中间人可以根据劫持的内容推送广告、电话骚扰或者实施网络诈骗等。

2、篡改风险

无法证明传输内容的准确度(即完整性),内容可能被篡改。

3、冒充风险

无法验证通信双方的身份,身份可能被冒充。例如:用户以为正在访问美团,但实际上访问的是伪装为美团的钓鱼网站,借此获取用户的账号、密码等重要信息。

HTTPS 是如何解决 HTTP 的安全问题?

1、加密-解决窃听问题

窃听问题是由于数据以明文的形式传输,因为为解决该问题自然会想到通过加密来解决。
加密算法主要分为可逆加密和不可逆加密:

  • 不可逆加密:加密后无法使用密钥解密出来,在此场景不适用;
  • 可逆加密分为对称加密与非对称加密:
    • 对称加密:通信双方使用同一个密钥加密、解密。
    • 非对称加密:有两个密钥,分别为公钥和私钥,公钥加密的内容只可被私钥解密,私钥加密的内容也只能被公钥解密。

对称加密与非对称加密相比,速度更快,因此优先考虑使用对称加密是否可以解决窃听问题。
为什么对称加密速度更快
Asymmetric encryption usually uses complex mathematical operations, such as power and modulus, on very large numbers (2048 bits). These operations take time.
Symmetric encryption uses simpler operations, such as XOR and multiply, on smaller numbers (64 or 128 bits). Hence they run faster.
对称加密一般针对小数位(64/128bits)使用异或操作和乘法操作,而非对称加密通常对大数(2048bits)进行取模或者幂运算,因此对称加密速度更快。
方式1:使用对称加密
image.png

中间人在没有密钥的情况下,即使获取到了密文,也无法解密查看具体内容,在此情况下可以保证数据传输的安全性。
但该方法存在一个漏洞,即如何保证小红和小蓝使用同一个密钥?更进一步理解是如何保证密钥在传输的过程中只让小红和小蓝知晓,而不被其他中间人(小紫)所监听。然而在对称加密的情况下,小红和小蓝在交换密钥的过程中必定是明文,因此对称加密无法解决密钥被窃取的问题,因而可以考虑引入非对称加密的方式解决。
方式2:使用非对称加密
image.png

因为公钥加密的内容只能被私钥解密且不会被传输,中间人即使截获了密文,也无法解密出相应的内容。因此可以利用非对称加密的方式传输密钥,防止密钥被窃听。
SSL/TLS 就是采用了非对称加密+对称加密的方式保证了数据的隐私性,利用非对称加密的方式确保密钥不被窃听,再利用对称加密的速度优势进行数据传输。

2、数字签名-解决篡改问题

image.png

数字签名:是通过哈希算法处理传输内容,生成摘要(Digest),将摘要通过私钥加密生成数字签名(Signature),并且连同原来的传输内容一同传输给接收方,接收方收到数据后,先通过公钥解密出对应的摘要,同时将传输内容以同样的哈希算法处理生成第二个摘要,两个摘要如果相等,则表明内容未被篡改。
哈希算法(Hash):也为摘要算法(Digest),对任意一组输入数据进行计算,得到一个固定长度的摘要,类比于公式 f(data) = key。其最大的特点为不可逆,即不能通过 key 逆推出 data。
Q:为什么要使用哈希算法,直接私钥加密生成数字签名可不可以?
可以,但是使用哈希算法可以减少计算量。 如果被签名的信息很大,签名是非对称算法,效率会非常低,所以会先做hash,hash后信息量有限,在签名效率就好了。
数字签名有两个功能

  1. 确保消息内容是来自于发送方(小红)【前提是接收方(小蓝)的公钥未被替换】;
  2. 确保内容未被篡改,保证了完整性;

image.png
数字签名需要通信双方拥有一对匹配的公钥和私钥,但是公钥要通过传输才能送到接收方(小蓝),如果在这个过程中有中间人(小紫)恶意截获了公钥,并且替换成与自己的私钥配对的公钥,那么接收方(小蓝)是无法辨别出公钥是否来自于发送方(小红),此时就需要引入 CA 机构来解决身份认证的问题。

3、数字证书-解决冒充/身份认证问题

CA(Certificate Authority,证书认证机构)为每个使用公钥的用户发放一个数字证书(Digital Certificate),数字证书的作用证明了这个公钥是属于该用户的。
image.png

身份认证过程:

  1. 小红将公钥、个人信息与其他信息提交给 CA;
  2. CA 通过线上、线下等多种手段审核小红提交的信息的准确性,审核通过后先用哈希函数处理小红的公钥匙,生成信息摘要,然后用 CA 的私钥加密小红的公钥,生成数字签名,将「数字签名+小红的公钥+小红的基础信息」组合成可小红公钥的数字证书;
  3. 由于上述的数字签名是通过 CA 的私钥加密生成的,则需要 CA 的公钥来解密,因此 CA 机构会为自身的公钥创建一个数字证书(CA 的数字证书),和小红的数字证书一同发送给小红;
  4. 小红将 CA 的数字证书 + 小红的数字证书一起发送给小蓝;
  5. 小蓝此时可通过 CA 的公钥解密小红数字证书中的数字签名,生成第一个信息摘要;
  6. 然后小蓝在通过哈希函数处理小红的公钥,生成第二个信息摘要;
  7. 如果这两个信息摘要完全一致,则可认定公钥确实属于小红,即完成了身份认证。

    4、如何证明 CA 机构是可信的

    目前而言没有一个完美的方案去证明 CA 机构完全可信,妥协的方案是将 CA 机构的证书内置到操作系统中,对于操作者而言默认信任内置的 CA 证书。
    但是由于 CA 机构过多,无法将所有的 CA 机构证书都内置到操作系统中,因此将 CA 机构又分为了根 CA 和中间 CA,根 CA 给中间 CA 颁发证书,中间 CA 可以给下一级的 CA 机构颁发证书,一般申请者都是向中间 CA 提交的申请。由于证书中会包含认证的机构,因此可以形成一个数字证书链。
    因此对于浏览器而言,可以通过证书链向上追溯,直至找到根证书,只要根证书是内置在操作系统中的,就认为是可信任的。
    image.png

    小结

  • 非对称加密+对称加密解决窃听问题;
  • 数字签名解篡改问题;
  • 数字证书解决冒充问题。

    HTTPS 工作流程

    2641864607-5e11d65c74244.png
    解决了 HTTP 中的三个安全性问题后,我们可以具体看下 HTTPS 的工作流程(以传统 RSA 版本的 HTTPS 为例)
    image.png

    传统 RSA 版本 HTTPS 的握手过程

    假设是客户端(一般是浏览器)发起的请求。
    1、第一次握手

  • 客户端所支持的加密通信协议(TLS)版本;

  • 客户端可支持的非对称加密和对称加密可支持的加密套件列表;
  • 客户端发送可支持的摘要算法;
  • 客户端生成第一个随机数 client-random(用于后续生成对称加密的会话密钥);

2、第二次握手

  • 服务器确认加密通信协议(例如 TLS)版本;
  • 服务器从非对称加密和对称加密套件中选定对应加密的算法;
  • 服务器选定摘要算法;
  • 服务器生成第二个 server-random(用于后续生成对称加密的会话密钥);
  • 服务器发送数字证书;

3、第三次握手

  • 客户端验证数字证书,验证通过则取到服务器的公钥,否则告警提示;
  • 客户端生成第三个随机数 pre-master(预会话密钥),利用服务器的公钥加密后传输给服务器;
  • 客户端根据协商好的加密算法,与三个随机数(client-random、server-random、pre-master)生成会话密钥(master-secret);
  • 客户端告知服务器后续将通过协商好的会话密钥与对称加密方法传输数据,并将上述所有的握手内容生成摘要 A,并用生成的 master-secret 加密生成数字签名,传输给服务器供服务器校验会话密钥。

4、第四次握手

  • 服务器接收到 pre-master,此时服务器也拥有了三个随机数,根据协商好的加密算法生成对应的会话密钥;
  • 服务器将握手内容生成摘要 B,同时用服务器生成的会话密钥解密接收到的数字签名取得摘要 A,对比摘要 A 和摘要 B,确认会话密钥的准确性。
  • 服务器告知客户端握手结束,后续将使用协商好的会话密钥进行通信。

Q:第三次握手为什么只需要用公钥加密 pre-master,如果被篡改/冒充怎么办?

  1. 篡改问题,因为被公钥加密的内容只能被私钥解密,而私钥只有服务器拥有,如果被篡改,那么服务器将无法解密,直接中断通信;
  2. 冒充问题,如果中间人截获了 pre-master,并且伪造了 pre-master-fake,且通过服务器的公钥加密,此时服务器虽然可以解密出 pre-master-fake,并用 pre-master-fake + client-random + server-random 生成 master-secret-fake,但由于客户端还会传输一份数字签名,此时由于 master-secret-fake 无法解密数字签名,直接中断通信。

Q:为什么需要三个随机数?
“不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。”

如何快速解决 HTTP 到 HTTPS 的转换?

1、通过 upgrade-insecure-requests 实现

通过后端或者前端设置 upgrade-insecure-requests 属性,可使浏览器在请求不安全(http)的资源前将其自动升级为 https,需要注意的是,如果请求的资源实际上无法通过 https 取得,那么会直接失败,不会回退到 http 的请求。
其次,这种方式无法改写通过 a 标签形式取得的资源。
1.1 前端通过 meta 实现
代码块
HTML


1.2 nginx 配置中设置 header
https://blog.csdn.net/qq_37788558/article/details/94752034

2、// 缺省协议

使用缺省协议 // 替代 http:// 与 https://,该方法可根据用户打开页面的协议,自适应补充页面资源的协议。例如:
代码块
HTML

//contract.sankuai.com/home
当前用户打开的是 https 协议的页面时,则上述地址表示为 https://contract.sankuai.com/home
当前用户打开的是 http 协议的页面时,则上述地址为 http://contract.sankuai.com/home
缺点:直接打开本地文件调试时,使用的协议是文件协议(file://)
优点:对于https页面的内容,浏览器默认会阻止非https内容,可以避免这种情况
Q:从 http 升级到 https 会有什么风险吗?
如果选择“强制https”,HTTP POST/PUT/DELETE 请求在302跳转到HTTPS的时候request body会被丢弃。
Q:站点升级了 https 之后,出现页面样式错乱的问题
因为页面中调用的静态资源不是 https 的请求形式,浏览器在加载的时候会产生告警,甚至无法加载 https 请求的 css 文件,导致出现非预期的页面样式。所以,升级测试期间,需要RD同学对页面调用的静态资源文件进行检查,采用 https 方式调用。若静态资源文件不支持 https 方式调用,建议协调将承载静态资源的服务升级为支持 https 请求,或将静态资源转移至支持 https 请求的服务中。
HTTP 升级 HTTPS 的注意点

  1. 确认资源文件是否可通过 https 方式取得;
  2. 检查 HTTP 的 POST/PUT/DELETE 请求内容是否被丢弃。

References:
https://mp.weixin.qq.com/s/eYaus8b3YYK3F8s2QTd71w
https://km.sankuai.com/page/1060625007