HTTP 不安全

http 协议属于明文传输协议,交互过程以及数据传输都没有进行加密,通信双方也没有进行任何认证,通信过程非常容易遭遇劫持、监听、篡改,严重情况下,会造成恶意的流量劫持等问题,甚至造成个人隐私泄露(比如银行卡卡号和密码泄露)等严重的安全问题。

可以把 http 通信比喻成寄送信件一样,A 给 B 寄信,信件在寄送过程中,会经过很多的邮递员之手,他们可以拆开信读取里面的内容(因为 http 是明文传输的)。A 的信件里面的任何内容(包括各类账号和密码)都会被轻易窃取。除此之外,邮递员们还可以伪造或者修改信件的内容,导致 B 接收到的信件内容是假的。

比如常见的,在 http 通信过程中,“中间人”将广告链接嵌入到服务器发给用户的 http 报文里,导致用户界面出现很多不良链接; 或者是修改用户的请求头 URL,导致用户的请求被劫持到另外一个网站,用户的请求永远到不了真正的服务器。这些都会导致用户得不到正确的服务,甚至是损失惨重。

HTTPS

超文本传输安全协议(HTTPS,(HyperText Transfer Protocol Secure)也被称为 HTTP over TLS,HTTP over SSL)是一种网络安全传输协议。它是一个安全通信通道。它是由 Netscape 开发并内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。

HTTPS 开发的主要目的,是提供对网络服务器的认证,保证交换信息的机密性和完整性。

vs HTTP

a、http 是普通的超文本传输协议,信息是明文传输,https 则是具有安全性的加密传输协议。

b、http 和 https 使用的是不同的连接方式用的端口也不一样,前者是 80,后者是 443。

c、https 协议需要到 ca 申请证书,一般免费证书很少,需要交费。

实现安全的方式

要解决 http 带来的问题,就要引入加密以及身份验证机制。

如果 Server(以后简称服务器)给 Client(以后简称 客户端)的消息是密文的,只有服务器和客户端才能读懂,就可以保证数据的保密性。

加密

所以很直接保护信息安全的方式就是给这段信息加密,那么选择何种加密方式呢?

对称加密

首先想到的加密方式,从原始简单的角度考虑,对信息的加密和解密都用同一种规则去做,用两把同样的钥匙去锁和开同一把锁。

这就是对称加密方式 (symmetric cryptography)。

这种对称加密算法比较流行的是 AES 算法,用一个统一的 key 来加密和解密数据,AES 使用数学矩阵的方式在数学上保证了,只要你使用的 key 足够足够足够足够的长,破解是几乎不可能的。但是对称加密的本质决定了它有两个问题。

  • 如果互联网每天有无数信息需要加密,一旦通信的实体多了,那么管理秘钥就会成为问题。

  • 客户端需要发送信息,用 AES 加密里信息数据,生成一个对应的 key,但是如何把这个 key 告诉服务端使用其进行解密呢?不管是和数据一起传给服务端,还是单独传给服务端都会经过网络传输,而这过程中不被发现和获取就很难了。

非对称加密

RSA 算法是目前最流行的公钥密码算法它使用长度可以变化的密钥。 RSA 是第一个既能用于数据加密也能用于数字签名的算法。

非对称加密相比对称加密更加安全,但也存在两个致命的缺点:

(1)CPU 计算资源消耗非常大。一次完全 TLS 握手,密钥交换时的非对称解密计算量占整个握手过程的 90% 以上。而对称加密的计算量只相当于非对称加密的 0.1%。如果后续的应用层数据传输过程也使用非对称加解密,那么 CPU 性能开销太庞大,服务器是根本无法承受的。赛门特克给出的实验数据显示,加解密同等数量的文件,非对称算法消耗的 CPU 资源是对称算法的 1000 倍以上。

(2)非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是 2048 位,意味着待加密内容不能超过 256 个字节。

所以非对称加解密(极端消耗 CPU 资源)目前只能用来作对称密钥交换或者 CA 签名,不适合用来做应用层内容传输的加解密。

缺陷

还是存在中间人攻击 + 信息抵赖

CA

https 协议中身份认证的部分是由 CA 数字证书完成的,证书由公钥、证书主体、数字签名等内容组成。

在客户端发起 SSL 请求后,服务端会将数字证书发给客户端,客户端会对证书进行验证(验证这张证书是否是伪造的?也就是公钥是否是伪造的),如果证书不是伪造的,客户端就获取用于对称密钥交换的非对称密钥(获取公钥)。

作用

1、身份授权。确保浏览器访问的网站是经过 CA 验证的可信任的网站。

2、分发公钥。每个数字证书都包含了注册者生成的公钥(验证确保是合法的,非伪造的公钥)。在 SSL 握手时会通过 certificate 消息传输给客户端。

3、验证证书合法性。客户端接收到数字证书后,会对证书合法性进行验证。只有验证通过后的证书,才能够进行后续通信过程。

申请一个受信任的 CA 数字证书通常有如下流程:

(1)公司(实体)的服务器生成公钥和私钥,以及 CA 数字证书请求。

(2)RA(证书注册及审核机构)检查实体的合法性(在注册系统里面是否注册过的正规公司)。

(3)CA(证书签发机构)签发证书,发送给申请者实体。

(4)证书更新到 repository(负责数字证书及 CRL 内容存储和分发),实体终端后续从 repository 更新证书,查询证书状态等。

证书链

如 CA 根证书和服务器证书中间增加一级证书机构,即中间证书,证书的产生和验证原理不变,只是增加一层验证,只要最后能够被任何信任的 CA 根证书验证合法即可。

二级证书结构存在的优势:

a. 减少根证书结构的管理工作量,可以更高效的进行证书的审核与签发;

b. 根证书一般内置在客户端中,私钥一般离线存储,一旦私钥泄露,则吊销过程非常困难,无法及时补救;

c. 中间证书结构的私钥泄露,则可以快速在线吊销,并重新为用户签发新的证书;

d. 证书链四级以内一般不会对 HTTPS 的性能造成明显影响。

CA 证书通常情况下是安全的。因为一旦某个 CA 颁发出的某个证书被用于了非法用途,浏览器和操作系统一般会通过更新将整个 CA 颁发过的全部证书全部视为不安全。 这使得 CA 通常在颁发证书时是比较小心的。

所以通过 对称加密 + 非对称加密 + CA 认证 这三个技术混合在一起,才使得 HTTP 的后面加上了一个 S —— Security。

其中任何一环稍有闪失,就会使得整个加密都将变得不安全。

这也是为什么 HTTPS 的加密协议从 SSL 1.0 升级到 SSL 3.0 再到 TLS 1.0 现在被 TLS 1.2 取代,其背后都是一环环细节上的修改,以防任何地方的闪失。

数字证书验证

申请者拿到 CA 的证书并部署在网站服务器端,那浏览器发起握手并接收到证书后,如何确认这个证书就是 CA 签发的呢?

怎样避免第三方伪造这个证书?答案就是数字签名(digital signature)。

数字签名是证书的防伪标签,目前使用最广泛的 SHA-RSA(SHA 用于哈希算法,RSA 用于非对称加密算法)。

数字签名的制作和验证过程如下:

1、数字签名的签发。首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用 CA 自己的私钥对消息摘要进行加密。

2、数字签名的校验。使用 CA 的公钥解密签名,然后使用相同的签名函数对签名证书内容进行签名,并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。

需要注意的是:

(1)数字签名签发和校验使用的非对称密钥是 CA 自己的公钥和私钥,跟证书申请者(提交证书申请的公司实体)提交的公钥没有任何关系。

(2)数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。(一对公钥和私钥,公钥加密的内容只有私钥能够解密;反过来,私钥加密的内容,也就有公钥才能够解密)

(3)现在大的 CA 都会有证书链,证书链的好处:首先是安全,保持 CA 的私钥离线使用。第二个好处是方便部署和撤销。这里为啥要撤销呢?因为,如果 CA 数字证书出现问题(被篡改或者污染),只需要撤销相应级别的证书,根证书依然是安全的。

(4)根 CA 证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的非对称密钥进行签名和验证的。

(5)怎样获取根 CA 和多级 CA 的密钥对?还有,既然是自签名和自认证,那么它们是否安全可信?这里的答案是:当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的根公钥都默认装到了浏览器或者操作系统环境里。

数据完整性验证

数据传输过程中的完整性使用 MAC 算法来保证。

为了避免网络中传输的数据被非法篡改,或者数据比特被污染,SSL 利用基于 MD5 或 SHA 的 MAC 算法来保证消息的完整性(由于 MD5 在实际应用中存在冲突的可能性比较大,所以尽量别采用 MD5 来验证内容一致性)。

MAC 算法是在密钥参与下的数据摘要算法,能将密钥和任意长度的数据转换为固定长度的数据。

发送者在密钥的作用下,利用 MAC 算法计算出消息的 MAC 值,并将其添加在需要发送的消息之后,并发送给接收者。

接收者利用同样的密钥和 MAC 算法计算出消息的 MAC 值,并与接收到的 MAC 值比较。

如果二者相同,则报文没有改变;否则,报文在传输过程中被修改或者污染,接收者将丢弃该报文。

SHA 也不能使用 SHA0 和 SHA1,山东大学的王小云教授(很牛的一个女教授,大家有兴趣可以上网搜索一下她的事迹)在 2005 年就宣布破解了 SHA-1 完整版算法,并获得了业内专家的认可。

微软和 google 都已经宣布 16 年及 17 年之后不再支持 sha1 签名证书。

HTTPS 传输过程

简单来说就是先进行 SSL/TLS 的安全通道建设,然后用加密协议加密数据,再进行基本的 HTTP 数据传递。

SSL 和 TLS 协议

SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL 通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。

TLS:(Transport Layer Security,传输层安全协议 ),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS 记录协议和 TLS 握手协议。

SSL 由从前的 Netscape 公司开发有 1, 2, 3 三个版本,但现在只使用版本 3,TLS 是 SSL 的标准化后的产物有 1.0 1.1 1.2 三个版本默认使用 1.0,TLS1.0 和 SSL3.0 几乎没有区别,事实上我们现在用的都是 TLS,但因为历史上习惯了 SSL 这个称呼平常还是以 SSL 为多。

TLS/SSL 的功能实现主要依赖于三类基本算法:散列函数 Hash、对称加密和非对称加密。

2018-08-25-https-alth.gif

TLS 握手:安全通道是如何建立的

2018-08-25-https-alth.gif

0 ms

TLS 运行在一个可靠的 TCP 协议上,意味着我们必须首先完成 TCP 协议的三次握手。

56 ms

在 TCP 连接建立完成之后,客户端会以明文的方式发送一系列说明,比如使用的 TLS 协议版本,客户端所支持的加密算法等。

84 ms

服务器端拿到 TLS 协议版本,根据客户端提供的加密算法列表选择一个合适的加密算法,然后将选择的算法连同服务器的证书一起发送到客户端。

112 ms

假设服务器和客户端协商后,得到一个共同的 TLS 版本和加密算法,客户端检测服务端的证书,非常满意,客户端就会要么使用 RSA 加密算法(公钥加密)或者 DH 秘钥交换协议,得到一个服务器和客户端公用的对称秘钥。

140 ms

服务器处理由客户端发送的秘钥交换参数,通过验证 MAC(Message Authentication Code,消息认证码)来验证消息的完整性,返回一个加密过的“Finished”消息给客户端。

168 ms

客户端用协商得到的堆成秘钥解密“Finished”消息,验证 MAC(消息完整性验证),如果一切 ok,那么这个加密的通道就建立完成,可以开始数据传输了。

在这之后的通信,采用对称秘钥对数据加密传输,从而保证数据的机密性。

性能优化

性能损耗

前文讨论了 HTTPS 原理与优势:身份验证、信息加密与完整性校验等,且未对 TCP 和 HTTP 协议做任何修改。

但通过增加新协议以实现更安全的通信必然需要付出代价,HTTPS 协议的性能损耗主要体现如下:

  • 加密 / 解密的过程是需要消耗时间

毕竟需要对传输的数据进行加密 / 解密,算法耗时是肯定有的。

  • 交换公钥 / 私钥消耗时间

https 传输在传输之前是需要再服务端与客户端交换公钥 / 私钥的,这个过程也是非常耗时的。有统计称 https 的链接耗时是 http 的连接耗时的 3 倍。

  • 跳转消耗时间

这里还有一个影响速度的点,那就是用户在浏览器中输入网址的时候,是不会去自己输入 https 协议头的,如果我们想要用户访问 https 的网站的话,就要自己进行一次网页重定向,重定向也是比较耗时的操作。这都会对我们的网站速度造成影响。

性能优化

  • 选择性的使用

假如为了安全保密,将一个网站所有的 Web 应用都启用 SSL 技术来加密,并使用 HTTPS 协议进行传输,那么该网站的性能和效率将会大大降低,而且没有这个必要,因为一般来说并不是所有数据都要求那么高的安全保密级别,所以,我们只需对那些涉及机密数据的交互处理使用 HTTPS 协议。

  • CDN 接入

HTTPS 增加的延时主要是传输延时 RTT,RTT 的特点是节点越近延时越小,CDN 天然离用户最近,因此选择使用 CDN 作为 HTTPS 接入的入口,将能够极大减少接入延时。

CDN 节点通过和业务服务器维持长连接、会话复用和链路质量优化等可控方法,极大减少 HTTPS 带来的延时。

  • 会话缓存

虽然前文提到 HTTPS 即使采用会话缓存也要至少 1 * RTT 的延时,但是至少延时已经减少为原来的一半,明显的延时优化;同时,基于会话缓存建立的 HTTPS 连接不需要服务器使用 RSA 私钥解密获取 Pre-master 信息,可以省去 CPU 的消耗。如果业务访问连接集中,缓存命中率高,则 HTTPS 的接入能力讲明显提升。

  • 硬件加速

为接入服务器安装专用的 SSL 硬件加速卡,作用类似 GPU,释放 CPU,能够具有更高的 HTTPS 接入能力且不影响业务程序的。测试某硬件加速卡单卡可以提供 35k 的解密能力,相当于 175 核 CPU,至少相当于 7 台 24 核的服务器,考虑到接入服务器其它程序的开销,一张硬件卡可以实现接近 10 台服务器的接入能力。

  • 远程解密

本地接入消耗过多的 CPU 资源,浪费了网卡和硬盘等资源,考虑将最消耗 CPU 资源的 RSA 解密计算任务转移到其它服务器,如此则可以充分发挥服务器的接入能力,充分利用带宽与网卡资源。远程解密服务器可以选择 CPU 负载较低的机器充当,实现机器资源复用,也可以是专门优化的高计算性能的服务器。当前也是 CDN 用于大规模 HTTPS 接入的解决方案之一。

  • SPDY/HTTP2

前面的方法分别从减少传输延时和单机负载的方法提高 HTTPS 接入性能,但是方法都基于不改变 HTTP 协议的基础上提出的优化方法,SPDY/HTTP2 利用 TLS/SSL 带来的优势, 通过修改协议的方法来提升 HTTPS 的性能,提高下载速度等。

前端影响

作用

  • 加密数据

你的网站如果有登录这种东西的话建议尽量使用 https 做,这样可以保证用户名、密码不被截获。

咱们平时使用的 post 请求中所带的用户名密码等,非常容易被获取到。

  • 反劫持

别以为劫持只是在你的网页里面插一些小广告,既然连广告都插得了,插一些 js 把你的 cookie 传到自己服务器上,也不是什么难事儿。亦或者做个钓鱼网页,让用户输入用户名和密码,也是非常容易的。所以,劫持是一件非常恐怖的事情。我们使用了 https 进行加密的话,则可以在大部分情况下规避这种危害。https 加密后,中间商们无法再随意向加过密的 html 内容中插入的自己的代码了。

  • SEO

其实谷歌对于 https 的网站,搜索结果会给予更高的排名。

国内的话,主要还是使用百度搜索引擎,但是百度搜索引擎目前只收录少部分的 https 网页,目前百度不主动抓取 https 页面(不了解)。

所以,如果是国内网站需要做 seo 的话,建议每张网页都提供 http/https 两种版本的访问方式。或者主页面、需要被抓取的页面使用 http 方式,而登录等功能采用 https 方式。

问题

  • HTTP 资源无法加载

在 https 环境下,http 协议的 js/css/ 请求 /iframe 等资源是根本加载不进来的

所以,如果想要使用这些资源的话,需要把访问这些资源的方式,转换为 https,我们称这种 https 页面中引用 http 资源的方式为” mix content”

  • HTTPS 下不能调用 HTTP 的异步请求

如果在 https 的页面中使用 http 的 ajax 调用。会提示跨域的报错,很明显有违 ip 地址、端口、协议的跨域限制。

解决办法

  • 相对地址

如果自己的静态服务器,两种协议均支持的话,则直接在引用资源的时候,去掉协议头,改为相对协议,

如 //xxx.com/a.js。这样,请求 a.js 这个资源的时候,浏览器会按照当前页面的协议,进行请求,这叫做 —–“协议相对地址”

对协议在放进标签、js 异步请求是都好用。但是当 url 的参数中需要加入 url 时,就不是很好用了。我们的“//”并没有成功,我们需要根据页面的情况加入协议,拼装成完整的 url,我们怎么获取协议呢?其实浏览器为我们提供了这种 API window.location.protocol

  • 做个 https 代理

如果自己的资源服务,不支持 https 访问的话,我们可以采用代理的方式,来引入这些文件。最简单的方式就是使用 nginx,将引入的静态文件均做个代理。也就是说,访问资源的时候,用的是咱们的代理地址,但是拿文件的时候,还是会去 http 的源地址去拿的。

  • 使用 HTTPS 资源和 HSTS

既然网站升级到了 HTTPS,那么资源及接口也应该一起对应升级为 HTTPS

如果用户在浏览器端,输入 www.jd.com 实际上,浏览器会默认将这个网址补全为 http://www.jd.com 而不是 https://www.jd.com。

于是乎,我们如果想让用户访问我们的 https 版本网站,还得将页面强行重定向 ( 跳转 ) 一下。这是一个比较耗时的操作。

而且有些时候,还没等我们重定向网页呢,就被运营商给劫持了。

这就需要 HSTS, 其实 HSTS 的做法比较简单,只要在用户访问网站的时候, 响应头中加入 ` Strict-Transport-Security` 这个头,浏览器接下来的访问就均会默认采用 https 的方式进行访问了。

参考资料

  • 安全协议

SSL/TSL

  • 加密算法

AES

RSA

  • https

https://medium.freecodecamp.org/https-explained-with-carrier-pigeons-7029d2193351

https://zhuanlan.zhihu.com/p/22142170

https://www.jianshu.com/p/650ad90bf563

https://juejin.im/entry/5aefc3b2518825670b33ff17

http://yunlaiwu.github.io/blog/2016/12/18/HTTPS%E5%AE%89%E5%85%A8%E6%80%A7%E5%8E%9F%E7%90%86%E4%BB%A5%E5%8F%8A%E5%85%B6%E5%AF%B9%E5%89%8D%E7%AB%AF%E7%9A%84%E5%BD%B1%E5%93%8D/

http://www.wxtlife.com/2016/03/27/%E8%AF%A6%E8%A7%A3https%E6%98%AF%E5%A6%82%E4%BD%95%E7%A1%AE%E4%BF%9D%E5%AE%89%E5%85%A8%E7%9A%84%EF%BC%9F/