CODE & ZEN

凯旋的博客

我是孙凯旋 @skx926
一名来自中国的 iOS 开发者
写过 Android
也会点 Web
深知付出更多才能收获更多
唯有在技术的道路上勤勤恳恳
方得片刻安心


深入理解HTTPS

HTTP为什么不安全

HTTP协议传输的数据都是未经过加密处理的,也就是说客户端和服务端使用HTTP通信的中间环节都有可能会产生信息的泄漏。

如何让HTTP更安全

有人会说很简单,把数据加密一下不就行了。嗯,说起来很简单,但是具体怎么加密呢?

对称加密还是非对称加密?

我们现在有两种加密方式可以选择:对称加密和非对称加密。

对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key),这种方法在密码学中叫做对称加密算法。

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

如果我们采用对称加密的方式,那么就需要将对称密钥以明文的方式从一方传递到另一方,这样的话密钥很容易被窃取,这样的加密也形同虚设。

如果我们使用非对称加密的方式,就需要将服务端的公钥在客户端发起请求之后传递给客户端,客户端使用服务端的公钥加密数据然后发送给服务端,服务端在接收到数据之后用自己的私钥进行解密就可以了。但是这样只是一个单向的加密。由于服务端的公钥是是公开的,任何一个人都可以获取,所以服务端用私钥加密后的数据是谁都可以解密的,所以也就不安全。

为了解决这个问题,我们可以让客户端也生成一对非对称的密钥,在获取到服务端的公钥之后,用其将客户端的公钥加密发送给服务端,服务端后面的数据都通过客户端的公钥进行加密再传输,这样就安全了。

但是这样的话又存在另外一个问题,就是效率问题。非对称加密的算法相对比较复杂,如果两端每次通信都使用非对称加密的进行加密的话,对通信的效率会有很大的影响。

既然非对称加密的效率比较低,那么我们是否可以将对称加密和非对称加密进行结合呢?答案是肯定的。我们可以在客户端获取到服务端的公钥之后生成一对对称密钥,然后发送给服务端。服务端在接收到之后后续的通信双方都使用对称密钥进行加密就可以在提高安全性的同时提升加密的效率。

如何保证服务端不会被冒充

到上一步我们似乎已经完美解决HTTP的安全问题了,但是新的问题又来了。如果在我们第一步客户端给服务器发送请求的时候会话已经被劫持,第二步我们收到的公钥也是假的,那我们后续的加密不都是白费力气?那么如何保证我们通信的服务器就是我们想要的服务器呢?

如果有两个人都说自己是小明,而你并不知道小明长什么样子,怎么判断谁是真正的小明呢?很简单,你可以要求他们亮出身份证,以此来确定谁是小明。同样的道理,两台服务器都说自己是google.com,我们可以要求每个服务器都去一个权威的机构(CA)申请一个唯一的身份证也就是数字证书,证书上写明自己的域名和公钥。这样客户端就可以通过他们的证书来判断谁是真正的google.com。

数字证书颁发过程:用户首先产生自己的密钥对,并将公共密钥及部分个人身份信息传送给认证中心。认证中心在核实身份后,将执行一些必要的步骤,以确信请求确实由用户发送而来,然后,认证中心将发给用户一个数字证书,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。用户就可以使用自己的数字证书进行相关的各种活动。数字证书由独立的证书发行机构发布。数字证书各不相同,每种证书可提供不同级别的可信度。可以从证书发行机构获得您自己的数字证书。

如何验证数字证书的真伪

那么问题又来了,既然有了数字证书将服务器地址和公钥绑定在了一起。那么又如何证明这个数字书是真的呢?

颁发数字证书的时候,CA将你提交的服务端身份信息和公钥写在证书上,然后使用一定的哈希算法从证书计算出一个摘要值,然后使用他们的私钥来对这个摘要值进行加密,然后添加到证书上。这段加密后的数据就叫做数字签名。

CA的公钥已经事先保存在了客户端所在的操作系统当中,所以当客户端收到服务端的数字证书之后就可以使用CA的公钥解密得到摘要值,然后通过同样的哈希算法对证书内容计算出一个摘要值并和解密得到的摘要值进行比对,如果完全相同则证明这个服务器就是我们想要通信的。之后就可以开心的进行握手的后续步骤了。

我们前面推演出的这个加密的过程其实就是HTTPS的工作过程。

什么是HTTPS

HTTPS全称是Hyper Text Transfer Protocol over Secure Socket Layer,顾名思义就是在HTTP的下面在加上一层SSL/TSL层以保证数据传输的安全性。

什么是SSL/TSL

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

SSL/TSL握手过程

关于SSL/TSL握手过程,这里有一篇阮一峰老师的文章已经讲解的很详细了:图解SSL/TLS协议,跟我们前面最终讨论出的结果相差无几,具体的过程这里就不多废话了。

中间人攻击和HTTPS调试

有人可能觉得HTTPS已经很安全了,即便有中间人他也只能干瞪眼,啥坏事也干不了。如果这样认为那你就大错特错了!

试想你不经意间安装了一个含有攻击者公钥的的根证书,然后在客户端和服务端握手阶段服务端发送的证书被攻击者截获,攻击者伪造一个身份信息和服务端证书相同但是替换成它的公钥的证书并用它的私钥进行签名。客户端在收到攻击者的证书之后由于系统中存在包含有攻击者的公钥的证书,所以可以成功的验证和解密收到的证书,然后客户端使用攻击者的公钥加密对称密钥发送给服务端时又被攻击者截获,这时攻击者使用自己的私钥解密获得对称密钥,然后再用服务端的公钥进行加密再发送给服务端。这样就在神不知鬼不觉中成功窃取了信息。

所以为了安全,我们在手机和电脑上安装证书时就要非常谨慎,防止重要信息被窃取。

但是同时这也给我们提供了一种HTTPS调试的思路:我们在调试接口时可能会需要查看HTTPS的报文真实内容,这对于HTTP来说很简单,直接用WireShark、Charles这类软件进行抓包就可以了。但是对于HTTPS就只能干着急,这时候我们就可以通过OpenSSL生成一个自签名的证安装在客户端来对HTTPS请求的内容进行查看。

利用SSL Pinning提高应用安全性

从上面我们知道HTTPS虽然已经足够安全,但还是存在中间人攻击的风险。SSL Pinning应运而生,SSL Pinning可以理解为证书绑定,也就是客户端事先内置一份服务端的证书,在通信的时候就把它和服务端发过来的证书进行比对,如果两个证书有任何的不同,就可以判定受到中间人攻击,马上可以中断请求。这样中间人就无法成功进行攻击了。

SSL Pinning虽然可以很好的解决中间人攻击问题,但是由于客户端要事先内置服务端的证书,所以只适用于客户端事先知道要请求的服务器的地址和证书的情况,比如iOS和Android应用与服务器之间的通信。像浏览器这种可以随意输入服务器的地址的场景SSL Pinning就无能为力了。

不同浏览器预装证书的差异

前段时间刚安装了新版的Firefox,打开别的网站速度都很快,但就是死活打不开google.com,会报证书不安全的错误,但同时使用Safari和Chrome都可以正常打开google.com。后来才发现是我在我是用的代理软件中开启了对google.com的https抓包(也就是是用中间人攻击的方式),把它关掉之后Firefox就可以正常访问google.com了,But why?直到我看到了知乎上的一个回答中的一句话之后才茅塞顿开:

证书是需要预装的,特别是根证书。IE和Chrome是通过内置在Windows系统中的TrustStore来管理根证书(当然自己也可以手动导入自签证书,浏览不会认可的因为有OCSP和CRL--之后细讲);而Firefox则是内置在自己的浏览中。

由于Firefox的所信任的根证书都内置在浏览器当中,并不会使用系统中的根证书,而我们自签名的证书只能安装在系统中,所以Firefox无法在内置的根证书中找到可以用来解密我们已经修改过的服务端证书,所以就会报错了。

最近的文章

iOS音视频的那些事儿(一):数据的采集和编码

AVFoundation简介 AVFoundation是苹果在iOS和OS X系统中用于处理基于时间的媒体数据的Objective-C框架. 供使用者来开发媒体类型的应用程序。 如果只是进行简单的视频录制,使用UIKit中的UIImagePickerController就可以了;如果需要播放视频, …

于  iOS 继续阅读
更早的文章

SSH协议工作过程

说到SSH,我们很多人都用过,比如我们通过git提交代码到Github的时候需要先添加本机的public key到Github网站,使用SSH远程连接VPS来对服务器进行操作。但是SSH究竟是什么,它是如何工作的呢? 定义 SSH全称Secure Shell,是一个提供数据通信安全、远程登录、远程指 …

于  Web 继续阅读
comments powered by Disqus