前言
本文结合自己学习和理解的情况,主要讲解 HTTPS 如何保障安全的概念性的内容,无硬核加密算法分析和抓包数据分析。
想要知道 HTTPS
是如何保障我们的安全的就需要先了解下面这三个前置知识。
为什么要有 HTTPS
?
因为 HTTP
协议不安全。
HTTP
是一个明文协议,整个传输过程是完全透明的,任何人都可以在链路中截获、修改或者伪造请求和响应报文,数据完全不可信。这样你打开一个网站,这个网站显示的内容到底是不是这个网站真实的内容是完全无法保障的,对于网上银行、网上购物这种场景来说更是致命的。现在的主流浏览器都会对 HTTP
协议的网站提示"不安全",极端的甚至直接默认设置下无法打开。
所以,我们就需要一个能保障安全的协议,也就是 HTTPS
协议。
HTTPS
是什么?
HTTPS
即 HyperText Transfer Protocol Secure
,超文本传输安全协议,这里的这个 S
我们也可以理解为 SSL/TLS
。
SSL
即安全套接层,Secure Sockets Layer。
TLS
即传输层安全,Transport Layer Security。
最早就是用的 SSL
,后来升级了,改名成立 TLS
,TLS1.0
实际上就是 SSL v3.1
。
目前(2023年) TLS1.3
是最新的,不过主流版本还是TLS1.2
,更早的版本不安全了,不建议使用了。
什么是安全?
通常认为,如果通信过程具备了四个特性,就可以认为是安全
的,这四个特性是:机密性、完整性、身份认证和不可否认。
-
机密性(Secrecy/Confidentiality):指对数据的"保密",只能由可信的人访问,对其他人是不可见的"秘密",简单来说就是不能让不相关的人看到不该看的东西。
-
完整性(Integrity,也叫一致性):是指数据在传输过程中没有被篡改,不多也不少,"完完整整"地保持着原状。
-
身份认证(Authentication)是指确认对方的真实身份,也就是"证明你真的是你",保证消息只能发送给可信的人。
-
不可否认(Non-repudiation/Undeniable),也叫不可抵赖,意思是不能否认已经发生过的行为,不能"说话不算数""耍赖皮"。
使用前三个特性,可以解决安全通信的大部分问题,但如果缺了不可否认,那通信的事务真实性就得不到保证,有可能出现"老赖"。
下面来讲一个"小红、小明和小强"的故事,来理解上面这四个特性。
小红和自己的闺蜜聊天,说自己喜欢小明,可是暗恋小红的小强正在隔壁房间偷听到了这段谈话,恨得小强在一旁咬牙切齿。这就是没有机密性。
小红给小明写了一张小纸条,内容是"明天早上十点XX公园见",悄悄放在小明的工位上,小强看见了,把内容篡改成了"明天早上我们一起来公司加班",然后小强明天早上十点去了XX公园。这就是数据在传输过程中被篡改,意思被完全扭曲了。
小强给小红写了一张纸条,内容是"我喜欢你",悄悄放在小红的工位上,她以为是小明写,欣喜若狂和给小明送了很多小零食,可是终究是空欢喜一场,因为小明喜欢的是小强。这就是身份无法认证带来的麻烦。
小红知道了小明不喜欢自己,于是找小明退还之前送给他的小零食,可是小明却说,你哪有送给我小零食,我凭什么给你,其实小明早吃完了,根本拿不出来。无法确定不可否认性,小明可以直接抵赖,拒不退还小零食,也不用赔钱。
综上所述,保证四个特性都具备,才能保证安全。
加密
实现机密性最常用的手段就是加密 ,加密之后的密文 谁也看不懂,只有使用专属密钥 解密只能才能看到原文,加密解密的操作过程就是加密算法。
可靠的加密算法都是公开的,任何人都可以对其进行分析研究,如果有人告诉你他们采用的加密算是自己搞的一套非公开的算法,那可真不一定靠谱,里面有什么漏洞,加密强度有没有他宣称的这么强都"全靠一张嘴"了。
按照密钥的使用方式,加密可以分为两大类:对称加密和非对称加密。
对称加密
加密和解密使用同一个密钥。
TLS 里有非常多的对称加密算法可供选择,比如 RC4、DES、3DES、AES、ChaCha20 等,但前三种算法都被认为是不安全的,通常都禁止使用,目前常用的只有 AES 和 ChaCha20。
AES 的意思是"高级加密标准"(Advanced Encryption Standard),密钥长度可以是 128、192 或 256。它是 DES 算法的替代者,安全强度很高,性能也很好,而且有的硬件还会做特殊优化,所以非常流行,是应用最广泛的对称加密算法。
非对称加密
对称加密看上去好像完美地实现了机密性,但其中有一个很大的问题:如何把密钥安全地传递给对方,术语叫"密钥交换"。
对称加密无法解决"密钥交互"的问题,所以就有了非对称加密。
非对称加密,有两把不同的密钥,一个叫公钥 (public key),一个叫私钥(private key),公钥可以给任何人使用,而私钥则需要严格保密。
公钥和私钥有个特别的"单向"性,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。
非对称加密可以解决"密钥交换"的问题。网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法破解密文。
RSA 可能是非对称加密算法中最著名的一个,它的安全性基于"整数分解"的数学难题,根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
过去 RSA 密钥的推荐长度是 1024,但随着计算机运算能力的提高,现在 1024 已经不安全,普遍认为至少要 2048 位。
混合加密
看上去,非对称加密似乎可以解决对称加密存在的问题,所以是不是可以抛弃对称加密了?
答案是否定的,因为非对称加密的效率实在是太低了,RSA 比 AES 的加密速率低了好几个数量级。
所以,要想实用性更好,就得把他们二者结合起来,混合加密。
通信刚开始的阶段,用非对称加密解决"密钥交换"的问题(这里的会话密钥通常很短,也不会花很长的时间), 后面的数据传输都使用对称加密算法来处理了。
解释一下上面的过程:
- 首先我们的客户端会获得网站的公钥;
- 然后会随机生成一个会话密钥,这个密钥使用公钥进行加密,传输到服务端;
- 服务端使用私钥解密出这个会话密钥,完成密钥交换;
- 服务端与客户端通信就可以使用对称算法进行加密和解密了。
至此,我们已经完美解决了机密性的问题。
摘要算法
经过了上面的加密,黑客虽然拿不到会话密钥,无法破解密文,但可以通过窃听收集到足够多的密文,再尝试着修改、重组后发给网站。因为没有完整性保证,服务器只能"照单全收",然后他就可以通过服务器的响应获取进一步的线索,最终就会破解出明文。
为了解决这个问题,就需要使用摘要算法了。
摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。
你可以把摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据"压缩"成固定长度、而且独一无二的"摘要"字符串,就好像是给这段数据生成了一个数字"指纹"。换一个角度,也可以把摘要算法理解成特殊的"单向"加密算法,它只有算法,没有密钥,加密后的数据无法解密,不能从摘要逆推出原文。
常见的加密算法有 MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1)、SHA-2,TLS 推荐使用的是 SHA-2,因为前面两者目前被认为是安全性较低的算法了。SHA-2 总共 6 种,常用的有 SHA224、SHA256、SHA384,分别能够生成 28 字节、32 字节、48 字节的摘要。
在发送消息的时候,我们会使用摘要算法,生成数字摘要,如果黑客修改哪怕了一丁点内容,摘要也会完全不同,消息被接收到之后一验证摘要就会发现消息被篡改过,不可信。
不过数字摘要本身不具有机密性,如果明文传输,那么黑客可以把摘要一并修改了,还是无法鉴别完整性。
所以摘要也得进行加密之后再传输,这就是哈希消息认证码(HMAC------Hash-based Message Authentication Code)。
到此为止,完整性的问题也解决了。
数字签名
机密性和完整性都解决了,我们的通信过程算是比较安全了,但是还是有漏洞,就是通信的两个端点无法验证彼此的身份。
黑客可以伪装成网站来骗取你的信息,也可以伪装成你向网站发送各种操作。
为了解决身份问题,我们需要一个只能是本人持有 ,但是大家又都能够方便辨认的东西,现实生活中,这样的东西可以是签名,也可以是印章。在数字世界里,我们叫他"数字签名"。
数字签名怎么获得呢?
- 首先,只能本人持有,非对称加密里面的私钥加密的摘要;
- 方便他人辨认,非对称加密的公钥可以解密,而公钥是公开的。
这就是数字签名的基本原理,有了他我们就可以同时实现身份证和不可否认两大特性。
数字证书
做完前面的所有工作之后安全四大特性都具备了,讲道理这样我们的通信应该就安全了吧?
很遗憾,答案是否定的。
还有一个"公钥信任"的问题需要解决,公钥谁都可以发布,如果黑客伪造了公钥,而你想访问某个网站的时候又正好输错了网址,进入到了一个和你的目标网站长得不能说很像吧,只能说一模一样的网站,而且你还在你们输入了你的用户、密码等信息,后果可想而知。
所以判断公钥是否可信就非常必要了,不得不说安全真的是一个麻烦的事情啊!
想要用类似密钥交换的方法来解决公钥认证的问题,用别的私钥来给公钥签名,显然,这会陷入无穷递归。
为了解决无穷递归的问题,我们只能给公钥认证找一个公认的可信的第三方,让他作为信任的起点,构建起公钥的信任链。
这个"第三方"就是CA(Certificate Authority,证书认证机构)。
CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成"数字证书"(Certificate)。
知名的 CA 全世界就那么几家,比如 DigiCert、VeriSign、Entrust、Let's Encrypt 等,它们签发的证书分 DV、OV、EV 三种,区别在于可信程度。DV 是最低的,只是域名级别的可信,背后是谁不知道。EV 是最高的,经过了法律和审计的严格核查,可以证明网站拥有者的身份。
不过,CA 怎么证明自己呢?
这还是信任链的问题。小一点的 CA 可以让大 CA 签名认证,但链条的最后,也就是 Root CA,就只能自己证明自己了,这个就叫"自签名证书"(Self-Signed Certificate)或者"根证书"(Root Certificate)。你必须相信,否则整个证书信任链就走不下去了。
有了这个证书体系,操作系统和浏览器都内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层地验证,直到找到根证书,就能够确定证书是可信的,从而里面的公钥也是可信的。
你自己生成的自签名证书,浏览器肯定是不会信任的,直接使用的话浏览器会提示不安全,但是如果你把你的证书安装进系统的根证书存储区里,让它作为信任链的根,就不会再有不安全提示了。
最后,CA 这个证书体系其实也不是绝对安全可信的,只是相对安全可信,因为 CA 万一被黑客攻陷了呢,或者 CA 作恶,所以安全没有绝对的安全。
双向认证和单向认证
前面说到两个端点交互数字签名、证书,但是这里有一个点要注意,就是双向认证和单向认证的问题。
普通的网站一般是用的单向认证,也就是客户端会去认证服务端的身份,而服务端并不需要认证客户端的证书,客户端的身份一般通过我们输入的用户名密码等进行认证就可以了。但是像网银这种对身份要求极高的场景,会有个 U盾啥的,给客户端也颁发一个证书,实现双向认证。