0. 前言
上一篇文章详细讲解了 HTTP 的相关原理,我们已经了解到了 HTTP 具有非常优秀和方便的一面,然而,HTTP 并非一个安全的协议。大家平常浏览网页的时候应该也能注意到,使用 HTTP 协议的网站,浏览器都会认定这是一个不安全的网站,提醒用户注意防范(即便这是我们学校的选课系统)。
当然,这个不安全的含义指的是你在该网页输入的信息可能会被外界攻击者以非正常手段窃取,而不是说会被这个网页的开发者获取,毕竟浏览器咋能判断这个网页开发者是否存有异心,这个需要用户自行判断(手动滑稽 😮)
那么为了克服 HTTP 的缺点,确保 Web 的安全,HTTPS 就应用而生了。可以看见,使用 HTTPS 协议的网页,地址栏前面都会有把小锁,表示这是一个加密安全的网站,你的信息发送到此站点时是保密的。而且 Google、Baidu 等搜索引擎巨头对于 HTTPS 网站都会给到更好的搜索排名。
本文会先解释 HTTP 为什么是不安全的,然后讲解 HTTPS 为了保证 Web 的安全提供了哪些手段,最后再揭晓谜底,为什么更安全的 HTTPS 协议在互联网上没有被全面采用。
1. 不安全的 HTTP
通过上面那张图我们已经知道,对于使用 HTTP 的网站,浏览器就会提醒我们请勿在此网站上输入任何敏感信息,否则可能会被攻击者窃取。没错,这就是 HTTP 协议不安全的表现,而且,仅仅是其中之一,HTTP 的不安全性体现在很多方面,例举如下:
- 通信使用明文(不加密),内容可能被窃听
- 不验证通信对方的身份,因此有可能遭遇伪装
- 无法证明报文的完整性,所以有可能被篡改
当然,这些问题不仅在 HTTP 上出现,其他未加密的协议中也存在类似问题
下面我们详细分析下上述问题出现的原因。
① 内容被窃听
所谓互联网,是由能连接到全世界的网络组成的,万物互联,无论世界哪个角落的服务器在和客户端进行通信时,在此通信线路上的网络设备、光缆、计算机都可能会遭到恶意窥视行为。也就是说,互联网上的任何角落都存在通信内容被窃听的风险。
而由于 HTTP 本身不具备加密的功能,所以也无法做到对 HTTP 请求和响应报文进行加密。
但是!即使是加密过的通信内容,也会被窥视到,这点和未加密的通信是相同的。只能说经过加密后的内容,即便被攻击者窥视到,他也可能无法破解其中的含义罢了,但是加密处理后的报文信息本身还是会被看到的,这点大家不要混淆了。加密后的内容尚且如此,更别说未加密的了。
② 身份被伪装
HTTP 的请求和响应不会对通信方进行确认,也就是说任何人都可以发起请求,而服务器对请求者来者不拒,只要接收到请求,就会返回一个响应。
显然,正是由于 HTTP 的这种简单性,导致了如下隐患:
1)客户端发送的 HTTP 请求报文可能到达的并非真正的目的服务器,可能是已伪装的服务器
2)服务器返回的 HTTP 响应报文可能也并没有被正确的客户端所接收,可能是已伪装的客户端
3)无法确定正在通信的对方是否具备访问权限
4)无法判定请求来自何方,出自谁手
5)即使是无意义的请求也会照单全收
③ 报文被篡改
HTTP 无法证明报文的完整性,所谓完整性就是指信息的准确度。若无法证明完整性,在 HTTP 请求或响应 送出之后直到对方接收的这段时间内,即使请求或响应的内容遭到攻击者篡改,也没有办法获悉。
通俗来说,HTTP 没有办法确认发送出去的请求和接收到的请求是否一致。
举个例子,你从某个使用 HTTP 的非正规网站上下载微信 APP,存放在服务器上的文件确实是微信 APP,但是,在你下载的过程当中,攻击者攻击了这个网站,你正在传输的文件内容被篡改成了其他文件,而在这个过程中,你是完全察觉不到的。
像这样的在请求或响应在传输途中,遭受攻击者拦截并篡改内容的攻击称为中间人攻击(Main-in-the-Middle attack, MITM)。
2. 安全的 HTTPS
HTTPS 协议并非应用层的一个新协议,只是 HTTP 通信接口部分用 SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议代替而已。
通常 HTTP 是直接和 TCP 进行通信的,当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 进行通信。简而言之。所谓 HTTPS,就是身批 SSL 协议外壳的 HTTP。
在采用 SSL 后,HTTP 就拥有了加密、证书和完整性保护等功能,而这些功能正是用来解决我们上述所说的 HTTP 不安全问题的。
另外,SSL 是独立于 HTTP 协议的,所有运行在应用层的协议都可以配合 SSL 协议使用。可以说,SSL 协议是当今世界上应用最为广泛的网络安全技术。
那么,针对上述 HTTP 的三个安全性问题,我们来看看 HTTPS 或者说 SSL 到底提供了哪些解决方案。
① 加密
这个上文也提到了,既然无法阻止被窃听,那么我就把我的内容加密起来,让你无法破解。那么,既然发送方对通信内容进行了加密,接收方接收到这个被加密过的内容,一定要知道对应的解密手段。
在讲解下述的几种加密方法之前,我们先理解密钥的概念。所谓密钥,就是钥匙,加密方有一把密钥,用来上锁,解密方也拥有一把密钥,用来解锁。而且加密方和解密方使用的密钥不一定是同一把。
共享密钥加密
加密和解密使用同一密钥的方式称为共享密钥加密(Common Key crypto system),也称做对称密钥加密(这个更好理解)。
以共享密钥加密时必须将密钥也发送给对方。显然,如果通信双方都各自持有同一个密钥,且没有别人知道,则两方的通信安全是可以被保证的(除非密钥被破解)。
那么,最大的问题就是如何保证这个密钥的安全传输,不被外部攻击者知道。如果由服务器生成一个密钥并传输给浏览器,这个传输过程中密钥被攻击者劫持,那么之后攻击者就能用这把密钥解开双方传输的任何内容。
发送密钥就有被窃听的危险,但不发送,对方就不能解密。怎么样才能安全的发送密钥?解决这个问题,我们就需要公开密钥加密(非对称密钥加密)。
公开密钥加密
公开密钥加密很好的解决了共享密钥加密的困难。
公开密钥加密需要一组非对称的密钥对,分别是公钥 public key 和私钥 private key。顾名思义,公钥可以随意发布,任何人都可以获得,而私钥不能让除通信双方外的其他任何人知道。这两个密钥是成对出现的,公钥加密的内容需要对应的私钥解密。
举个例子:客户端(浏览器)想要给网站服务器发送消息
- 首先,网站服务器持有一组公钥和私有,它会把自己的公钥明文传输给客户端
- 客户端利用这个公钥给自己的消息进行加密,然后传输给服务器,这时候就算被攻击者截获,由于攻击者没有对应的私钥也无法解密该内容
- 网站服务器收到后,使用这个公钥对应的私钥进行解密
利用这种方式,不需要发送解密需要的私钥,也就不必担心私钥被攻击者盗走
混合加密方式
上述公开密钥加密的方式虽然安全,但是相比于不那么安全的共享密钥加密方式来说,其处理速度要慢很多。HTTPS 综合这两种加密方式的优势,使用共享密钥加密要发送的信息,使用公开密钥加密这个共享密钥,这样就减少了公开加密的次数。举个例子:
- 某网站服务器拥有一组用于公开密钥加密的非对称密钥:公钥 A1、私钥 A2
- 浏览器向网站服务器请求,服务器把公钥 A1 明文给传输浏览器
- 接收到这把公钥 A1 后,浏览器随机生成一个用于共享密钥加密(对称加密)的密钥 X,用公钥 A1 加密后传给服务器。这个阶段,即便被攻击者截获,由于攻击者没有对应的私钥也无法解密该内容
- 服务器拿到后用对应的私钥 A2 解密得到密钥 X(以上这些阶段就是公开密钥加密)
- 这样双方就都拥有密钥 X 了,且别人无法知道它。之后双方之间所有的数据传输都使用密钥 X 进行加密和解密即可(这个阶段就是共享密钥加密)
② 数字证书
遗憾的是,上述混合加密的方式仍然还是有漏洞的。攻击者(中间人)的确无法得到浏览器生成的对称密钥 X,这个密钥本身被公钥 A1 加密,只有使用服务器拥有的私钥 A2 才能解密。但是!攻击者完全不需要拿到服务器私有的私钥 A2 就能劫持信息。举个例子:
- 某网站服务器拥有一组用于公开密钥加密的非对称密钥:公钥 A1、私钥 A2
- 浏览器向网站服务器请求,服务器把公钥 A1 明文给传输浏览器
- 攻击者劫持到公钥 A1,保存下来,把数据包中的公钥 A1 替换成自己伪造的公钥 B1(它当然也拥有公钥 B1 对应的私钥 B2)
- 浏览器随机生成一个用于对称加密的密钥 X,用攻击者的公钥 B1(服务器此时不知道自己的公钥被替换了)加密后传给服务器
- 攻击者劫持后用自己的私钥 B2 解密就得到了密钥 X。然后再用服务器的公钥 A1 加密后传给服务器
- 服务器接收到攻击者用公钥 A1 加密的信息后,用对应的私钥 A2 解密得到密钥 X
这样在客户端浏览器和网站服务器都没有发现异常的情况下,攻击者得到了对称密钥 X。此后客户端和浏览器双方通过对称密钥 X 加密发送的任何内容,攻击者都可以轻松破解。
上述过程就是典型的中间人攻击,其根本原因是浏览器客户端无法确认自己收到的公钥是不是真正的网站服务器的。那么下一步就是解决这个问题:❓ 如何证明浏览器客户端收到的公钥一定是该网站服务器的公钥?防止服务器和客户端的身份被伪装。
其实很简单,大家想一下在现实生活中,如何证明小明说出的身份证号确实是它自己的,怎么办?看看小明的身份证就可以了。身份证是由谁颁发的?政府机构。那么这里政府机构就起到了公信的作用,它本身的权威可以对一个人的身份信息作出证明。
对应的,互联网中也有这么一个公信机构,数字证书认证机构 Certificate Authority, CA。所谓公信机构,就是客户端和浏览器都信赖的第三方机构。
网站服务器在使用 HTTPS 前,需要向 CA 申请颁发数字证书,数字证书里有证书持有者、证书持有者的公钥等信息。服务器把数字证书明文传输给浏览器客户端,然后浏览器从证书里取出服务器的公钥就可以了。
然而这里又有一个显而易见的问题:证书本身的传输过程中,如何防止被篡改?即如何证明证书本身的真实性? 数字证书怎么防伪呢?
③ 数字签名
数字证书认证机构 CA 在判明提出申请者的身份之后,会对其申请的公开密钥做数字签名,然后将数字签名和公开密钥放入数字证书。而客户端在收到服务器发送来的数字证书后,对证书上面的数字签名进行验证,如何这个数字签名和证书上的原始公开密钥 Hash 后的结果一致,那么客户端便可明确两件事情:
- 认证服务器的公开密钥的是真实有效的数字证书认证机构
- 服务器的公开密钥是值得信赖的
OK,这么说还不太清楚,我们先来了解什么是数字签名?
数字证书认证机构 CA 把要传送的明文信息(也就是申请认证的网站服务器的公钥)通过 Hash 算法得出摘录信息 MIC(摘录技术),再用自己的私钥对 MIC 值进行加密,就得到了得到数字签名。
解释一下:认证机构一般会持有一组公钥 A1 和私钥 A2,为了确保证书的安全性,浏览器客户端通常会在内部事先植入常用认证机构的公钥 A1,认证机构在颁发数字证书的时候,会用自己的私钥 A2 对数字签名进行加密。而浏览器接收到数字证书后,先利用事先存储好的公钥 A1 解密数字签名,再对数字签名进行验证。
下面是这个过程的总结提炼,大家配合图片直观理解一下。
1)CA 颁发数字证书给网站的过程:
- CA 拥有非对称加密的私钥和公钥
- 网站申请数字证书,并发送自己的公开密钥 A
- CA 对网站的公开密钥 A 进行 Hash 得到摘录信息 MIC
- 对 MIC 值用 CA 的私钥加密,继而得到数字签名
- 将数字签名和网站的公开密钥 A 放进数字证书发放给网站
2)浏览器客户端验证网站数字证书的过程:
- 浏览器客户端接收到网站服务器发来的数字证书,得到网站的公钥 A 和数字签名 S1
- 浏览器使用事先植入的 CA 机构的公钥对 S1 进行解密,得到 S2
- 用数字证书里说明的 Hash 算法对网站的公钥 A 进行 Hash 得到 A2。
- 比较 S2 是否等于 A2,若相等则表示证书可信。于是浏览器就可以放心的取出数字证书中的网站公钥 A 进行使用
3. 为什么 HTTPS 没有被全面采用
回到文章标题,既然 HTTPS 安全可靠,那为什么不所有的 Web 网站都使用 HTTPS 呢?
其中一个原因就是,由于使用了加密通信, 相比于纯文本通信的 HTTP 来说,HTTPS 会消耗掉更多的 CPU 及内存资源,如果每次通信都加密,会消耗掉非常多的资源,平摊到一台计算机上时,能够处理的请求数量必定也会随之减少。一些国际大型网站比如维基百科等,在启用 HTTPS 前都会先考虑自己服务器资源和计算能力是否可以承载 HTTPS。
因此,如果是非敏感信息,使用 HTTP 通信也无妨。只有在涉及个人敏感信息等数据时,才需要使用 HTTPS。
另外,开启 HTTPS 需要申请 SSL 证书,高额的证书申购费用会让很多网站开发者望而却步。
看到这里,不知道大家能不能够理解为什么基本上所有学校的选课系统全是 HTTP 了:
- 首先,大部分选课系统基本都需要校园网或者 VPN 才能够登录,不需要考虑被外界攻击或者信息泄露问题
- 其次,即便使用的是 HTTP,选课系统开放的初期猛量的高并发尚且会让服务器崩溃,就甭说 HTTPS 了
所以综合来说,校内选课系统完全没必要增加额外的运行和维护成本来使用 HTTPS。
😁 下方扫码关注_公众号_「飞天小牛肉」(专注于分享计算机基础、Java 基础和面试指南的相关原创技术好文,帮助读者快速掌握高频重点知识,有的放矢),与小牛肉一起成长、共同进步
🎉 并向大家强烈推荐我维护的 _Gitee 仓库_ 「CS-Wiki」(Gitee 推荐项目,目前已 0.9k star。面向全栈,致力于构建完善的知识体系:数据结构、计算机网络、操作系统、算法、数据库、设计模式、Java 技术栈、机器学习、深度学习、强化学习等),相比公众号,该仓库拥有更健全的知识体系,欢迎前来 star,仓库地址 CS-Wiki(Gitee 推荐项目,0.9k star)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。