HTTPS简介
超文本传输安全协议(HTTPS,常称为 HTTP over TLS/SSL)是一种通过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
HTTPS如何保证数据传输的安全性
TLS/SSL
-
TCP (Transmission Control Protocol)
传输层控制协议 -
TLS (Transport Layer Security)
传输层安全协定 -
SSL (Secure Socket Layer)
安全套接层
HTTP(Hypertext Transfer Protocol)
基于 TCP
协议,无连接,每次连接只处理一个请求,结束后断开连接;无状态,无法保持用户状态,使用 cookie
和 session
解决。
HTTPS(HTTP over TLS/SSL)
安全的 http
协议,HTTP
协议和 TCP
协议之间增加了 TLS/SSL
保证数据的安全传输。
历史进程:
1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。
1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。
1996年,SSL 3.0版问世,得到大规模应用。
1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版。
2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。最新的变动是2011年TLS
1.2的修订版。
TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。
目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的支持。
HTTPS安全性
HTTP 协议的不安全性体现在四个方面:
风险 | 描述 | https解决方案 |
---|---|---|
窃听风险 | 攻击者可以获知消息内容 | 消息加密 |
篡改风险 | 攻击者可以篡改消息内容 | 消息摘要 |
冒充风险 | 攻击者可以冒充其它人参与通信 | CA身份认证 |
CA 不可信 | 信任的CA乱签发证书 | 证书锁 |
窃听/嗅探
解决方案:
- 使用对称加密算法加密通信内容,窃听者获取到消息也无法识别,存在问题
->
密钥传递的安全性,在网络上面的通信双方都是陌生人,无法识别身份,密钥要通过网络传输时很有可能被窃取。❌ - 使用非对称加密算法加密通信内容,客户端用发布的公钥用来加密,服务端用私钥用来解密,即使公钥被窃取,依然无法解密消息内容。存在问题 -> 速度慢,消耗大;公钥被公开,如果回发私钥加密的信息,任何持有公钥的人都可以解密。❌
- 最终,消息内容仍旧使用对称加密算法来加密,但是前期对称加密的密钥交换使用非对称加密来进行,客户端使用服务端公钥加密对称加密的密钥,这样就只有拥有私钥的服务端可以获取到加密内容,由于对称加密密钥长度有限,加密的时间可以忽略不计。✅
以上,可以防止嗅探的问题,路由上面的攻击者即使获取到消息也无法识别消息的内容。
篡改消息
消息加密以后攻击者无法获取消息内容的含义,但是可以篡改消息内容,篡改之后接收方也无法感知。
解决方案:
- 采用消息摘要算法可以验证数据的完整性,我们将发送的消息进行摘要,连同消息一起发送给接收方,接收方拿到消息之后对消息做同样的摘要处理,对比摘要结果,即可知道消息有没有被篡改。
以上,可以解决消息完整性和真实性的问题。
中间人冒充攻击
中间人攻击(Man-in-the-middle Attack,MITM
)指的是攻击者在链路上伪装自己,与通讯双方分别建立联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
作为 A 和 B 通信路由上的攻击者 M,作为中间人伪造自己的身份。A 向 B 请求用于通信的 公钥PK_A
,但是被中间人 M 截获,他伪造生成了假的公钥 PK_M
,发送给了 A,同时向 B 请求并获取了 B 的公开密钥 PK_B
,原来安全的通信过程: A(使用公钥PK_B 加密) -> 安全 -> B(使用私钥SK_B 解密)
;现在变成了A(使用 PK_M 加密) -> M(使用 SK_M 解密获取明文内容,再用 PK_B 加密,可能篡改数据) -> B(使用 SK_B 解密)
。
出现问题的原因在于,密钥在交换的初期是不安全的,网络上的通信双方,无法确定对方的身份,即无法获悉当前的公钥是不是自己想要的公钥。
解决方案:
- 引入第三方公正作信用背书,第三方公正具有权威性,他和通信双方没有关系,接收方无条件信任公证机构,也就会信任他签名的信息。这种机构被称为
CA(Certificate Authority)
机构,即数字证书认证机构。CA 机构与浏览器和操作系统厂商合作,将公钥内置在浏览器和操作系统中,也就是不走网络传输了,这样一定程度上保证了公钥不会被窃取篡改。 - 服务端
Server
将自己的消息(消息内容大致包括:电子签证机关的信息、公钥用户信息、公钥、权威机构的签字和有效期等)进行摘要之后,发给CA
机构AUTH
签发证书,Server
将证书和消息内容发送给Client
,Client
收到后,发现是AUTH
的证书,同时对AUTH
是信任的,则会使用AUTH
的公钥对证书进行解密(这里涉及证书链的验证,其实要更加复杂),获取到消息摘要,同时对收到的消息进行摘要,对比,如果一致则说明内容没有被篡改,是可信的,因为生成加密数据的私钥只有CA
机构才有,这一过程称为验证数字签名。
以上,可以解决中间人攻击的问题,另外涉及到非对称加密的两种应用场景,详细介绍见文末[非对称加密应用场景]
CA 错误签发
受信任的 CA
(证书颁发机构)有好几百个,他们成为整个网站身份认证过程中一个较大的攻击面。实际上,目前由于 CA
失误导致错误签发证书,以及个别 CA
出于某些目的(如监控加密流量)故意向第三方随意签发证书,这两种情况时有发生。现有的证书信任链机制最大的问题是,任何一家受信任的 CA
都可以签发任意网站的站点证书,这些证书在客户端看来,都是合法的,是可以通过验证的。
解决方案:
- 证书锁(Certificate Pinning),证书锁是为了防范由 「伪造或不正当手段获得网站证书」 造成的中间人攻击。
- 证书锁类似于
HPKP
技术(下面有简单介绍),给予我们主动选择信任CA
的权利。它的工作原理就是使用预先设置的证书指纹和服务器传过来的证书链中的证书指纹进行匹配,只要有任何一对指纹匹配成功,则认为是一次合法的连接,否则禁止本次链接。 - 也就是说,使用证书锁之后,不是所有被系统信任的
CA
都可以通过验证,只有我保存了指纹的一些CA
签发的证书才可以,比如有 100 个CA
机构,但我就信任其中一个,我可以保证这个CA
不会乱签发证书,那我就只保存这个CA
的指纹,即使攻击者从其他的 99 个CA
签发证书,对我进行攻击,也无法完成连接。 - 证书锁定增加了安全性,但限制了你的服务器团队升级
TLS
证书的能力。
以上,可以解决 CA 机构签发证书权威性不足的问题,相关解决方案详见文末 [签发证书权威性问题]
HTTPS安全保证
🔥 综上所述,对称加密通信
+ 非对称加密交换密钥
+ CA 认证身份
+ 证书锁锁定证书指纹
共同保证了HTTPS的安全性。
CA 安全性
作为全网 Https
连接的权威公正,CA
的安全性至关重要。
安全保存 CA
从根 CA
开始到直接给客户发放证书的各层次 CA
,都有其自身的密钥对。 CA
中心的密钥对一般由硬件加密服务器在机器内直接产生,并存储于加密硬件内,或以一定的加密形式存放于密钥数据库内。加密备份于 IC
卡或其他存储介质中,并以高等级的物理安全措施保护起来。
密钥的销毁要以安全的密钥冲写标准,彻底清除原有的密钥痕迹。需要强调的是,根 CA
密钥的安全性至关重要,它的泄露意味着整个公钥信任体系的崩溃,所以 CA
的密钥保护必须按照最高安全级的保护方式来进行设置和管理。 CA
的私钥是自己靠上述方法保管的,不对外公开。
所以 CA
密钥的安全性依赖于物理硬件的安全性,不通过网络传输避免了被攻击的可能。
CA
的公钥是厂商跟浏览器和操作系统合作,把公钥默认装到浏览器或者操作系统环境里。比如 firefox
就自己维护了一个可信任的 CA
列表,而 chrome
和 IE
使用的是操作系统的 CA
列表
证书验证
证书是否是信任的有效证书
- 是否信任 :接收方内置了信任根证书的公钥,需要验证证书是不是这些信任根证书签发的或者信任根证书的二级证书机构颁发的。
- 是否有效:证书是否在有效期内。
- 是否合法:对方是不是上述证书的合法持有者,证明对方是否持有证书的对应私钥。验证方法两种,一种是对方签个名,我用证书验证签名;另外一种是用证书做个信封,看对方是否能解开。
- 是否吊销:验证是否吊销可以采用黑名单方式或者
OCSP
方式。黑名单就是定期从CA
下载一个名单列表,里面有吊销的证书序列号,自己在本地比对一下就行。优点是效率高。缺点是不实时。OCSP
是实时连接CA
去验证,优点是实时,缺点是效率不高。
自签名证书如何验证
自签名证书是自己给自己签发的证书,也就是说自己做自己的 CA
机构,为自己担保,因此无法内置在系统当中,因此我们通常会在客户内置一个证书文件,自己进行校验。
简单来说,握手流程需要两对密钥对:
- 一对
CA
的密钥对JKS_A
,由CA
机构维护,通常他的公钥内置在os
中,用来签名服务端信息摘要,保证服务端公钥的真实性,避免中间人攻击。 - 一对服务器的密钥对
JKS_B
,他是握手过程中随机生成的,然后用「它的公钥及其他内容」的摘要去向CA
实时签发证书,用来进行对称密钥的加密传输。
自签名证书就是不走 CA
机构,而是自己生成一对密钥对 JKS_C
,他的作用就好比 CA
的密钥对 JKS_A
,也是为了保证公钥的真实性,握手过程和原来一样,只是我们不需要去 CA
签发证书了,用自己的 JKS_C
签发就可以了;同样因为 JKS_C
是我们自己的密钥对,公钥没有被内置在 os
中,所以此时需要我们自己把 cert
文件(JKS_C
的公钥)放到本地,自己完成原本由 os
完成的 CA
校验任务。
双向验证
双向验证指的是,不光客户端要验证来自服务器的连接是不是可靠,服务器也要验证客户端。
服务端也会内置一套受信任的 CA 证书列表,用于验证客户端证书的真实性。验证过程和客户端验证服务端类似。
HTTPS握手
单向验证过程
-
-
Client Hello ➡️
-
客户端向服务器发送握手信息,告知自己支持的
加密算法、
摘要算法、
(TLS)安全层协议版本、
随机数
Random-Secret-C
。
-
客户端向服务器发送握手信息,告知自己支持的
加密算法、
摘要算法、
(TLS)安全层协议版本、
随机数
-
-
Server Hello ⬅️
- 服务端随机生成本次握手需要的 非对称加密的 密钥对(私钥+公钥), 将来用来传输 对称加密 密钥。
-
服务端生成消息,内容包含随机数
Random-Secret-S
,确定的一组 加密算法和 摘要算法, 服务端公钥, 域名信息等。 -
服务端对
信息内容
摘要,使用服务端消息和消息摘要向
CA
机构申请的 签名证书。 - 服务端向 客户端发送 申请的证书。
如果需要双向验证的话,请求客户端证书。
-
-
验证服务端证书,提取服务端公钥 ➡️
-
客户端从信任证书列表中发现是受信任的证书,会首先验证证书是否被信任、有效性、合法性等信息,验证过程参照上面的证书验证。(
CA
用 私钥对服务端消息和摘要进行签名形成 签名证书,客户端用 公钥解密 签名证书,验证 签名) -
客户端验证通过,然后使用
CA
机构的 公钥对证书 解密,拿到 消息摘要和服务器消息,然后对服务端消息内容进行 摘要,对比消息摘要,确定 消息内容没有被篡改,则提取 服务端公钥。 -
客户端生成随机数字
Pre-Master-Secret
(预主密钥),将其进行摘要处理,使用 服务端公钥对消息和摘要结果加密,发送给服务器,并发送一个编码 改变通知,说明以后将会开始加密通信。
-
客户端从信任证书列表中发现是受信任的证书,会首先验证证书是否被信任、有效性、合法性等信息,验证过程参照上面的证书验证。(
-
-
生成对称加密密钥 ⬅️
-
服务器使用
私钥对收到的信息
解密 获得客户端消息和摘要,对消息进行
摘要处理,和客户端发来的摘要进行对比,无误,则说明
对称加密的
预主密钥(
Pre-Master-Secret
)没有被篡改,然后使用Random-Secret-C
,Random-Secret-S
,Pre-Master-Secret
生成 最终将要进行 对称加密通信的 主密钥Master-Secret
。 -
服务器使用主密钥
Master-Secret
加密一段握手信息及其摘要,发送给客户端,并发送一个编码改变通知,说明以后将会开始加密通信。
-
服务器使用
私钥对收到的信息
解密 获得客户端消息和摘要,对消息进行
摘要处理,和客户端发来的摘要进行对比,无误,则说明
对称加密的
预主密钥(
-
-
客户端验证加密结果,握手结束 👌
-
客户端使用
Random-Secret-C
,Random-Secret-S
,Pre-Master-Secret
生成同样的 对称加密 密钥Master-Secret
,使用密钥 解密服务端消息,获得消息和摘要,并对消息 摘要处理和服务端 摘要对比,没有问题则握手结束。
-
客户端使用
后面的通信将会使用新生成的对称加密密钥
Master-Secret
加密进行。
握手流程图
脑洞大开
Q:为什么要有 3 个随机数?
不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于 SSL 协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。对于RSA密钥交换算法来说,Pre-Master-Secret 本身就是一个随机数,再加上 hello 消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
Pre-Master 的存在在于 SSL 协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么 Pre-Master-Secret 就有可能被猜出来,那么仅适用 Pre-Master-Secret 作为密钥就不合适了,因此必须引入新的随机因素,那么客户端
Random-Secret-C
和服务器Random-Secret-S
再加上Pre-Master-Secret
三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"
Q:放在 Android 客户端的 cert 文件是啥?
是自签名证书的公钥,自签名证书就是自己做自己的
CA
机构,服务端会自己维护一个密钥对JKS
,他就相当于CA
的签发证书的密钥对,在握手过程中服务器不需要走CA
申请签名证书了,自己签发就可以,原本CA
的公钥被内置在os
中,CA
的验证不需要我们来关注,但是现在是自签名的,自己做自己的CA
,所以JKS
的公钥我们要内置在客户端中,自己完成验证过程,替代原来os
的验证。
证书工具-keytool
提取证书内容为一个字符串
keytool -printcert -rfc -file [srca.cer]
生成密钥对
keytool -genkey -alias [march_server] -keyalg RSA -keystore [march_server.jks] -validity 3600 -storepass [123456]
读取密钥对信息
keytool -list -v -keystore [srca.jks] -storepass [123456]
提取公钥,签发 cert 文件
keytool -export -alias march_server -file march_server.cer -keystore march_server.jks -storepass 123456
将客户端公钥导入客户端密钥对中,主要是服务器不能使用 cert 证书,需要导入到 jks 文件中
keytool -import -alias [march_client] -file [march_client.cer] -keystore [march_client_for_server.jks]
注脚
消息摘要(Message Digest
)
指的是将长度不固定的参数作为输入参数,运行特定 hash 函数,生成固定长度的输出,这个输出就是消息的摘要,常用算法有 MD5 和 SHA1,摘要算法是单向不可逆的,即无法从摘要重新反向出原消息的内容。
信用背书
票据的收款人或持有人在转让票据时,在票据背面签名或书写文句的手续。背书的人就会对这张支票负某种程度、类似担保的偿还责任。
非对称加密的两种应用场景
- 某用户使用自己的私钥对数据加密,任何人都可以使用公钥对数据进行解密,因为私钥只有该用户持有,则说明该数据一定出自于该用户。公众可以用这一方法验证内容是否完整,是否被篡改,接受者可以认定该内容出自该用户,该用户也无法抵赖,这被称作数字签名。
- 某用户使用公开的公钥对数据进行加密,那么可以保证只有发布公钥的一方可以对数据进行解密,别人无法获取数据的内容,保证数据传递的安全。