HTTPS 的两三事
今天我们的某条业务线终于使用上了HTTPS
。 因为实在是忍受不了某动,某通等运营商的内容劫持。不但会嵌入广告, 而且会嵌入一些js代码,导致整个web都崩溃掉。在这个过程中也比较深入的了解了一下HTTPS
协议。这里做一个记录。
实际上HTTPS
我个人理解起来就是 HTTP over TLS(transport layer security), 因此本篇文章的重点也就是TLS的协议。 我们将重点分析TLS是如何建立起来的,以及https 的 hack 方法。
一些基础姿势
RSA
关于RSA加密相信每一个搞计算机的人可能都了解过(但弄明白的很少吧, 数学的东西推导起来头都大了)。非对称加密,故名思意也就是用公钥来加密的,用私钥来解密 。这也是我一开始对于RSA的认知。然而也听说过RSA可以用做签名, 用私钥签名用公钥来验证签名。对于这一点我感到非常的迷惑。How it works? 原来用私钥加密的内容,可以用公钥来解密。公钥和私钥的称谓可能本身具有一定的迷惑性,然而他们本身没有什么本质的区别,用一把钥匙加密,用另一把钥匙解密,这是个双向的。
RSA的证明太过复杂,我们也不做赘述。这里只说两个结论
- 加密过程: 用公钥来加密后得到密文,用私钥可以解出平文
- 签名过程: 用平文生成一个摘要,用密钥加密这个摘要。 验签过程就是用公钥解密摘要并重新用获得的平文生成摘要进行对比。(之所以不加密整个的平文,可能就是出于性能考虑吧,反正公钥是发布出去的,其实加密了每个人依旧能得到)
另外非对称加密的方式也不只有RSA一种,比如后面我们提到的Diffie–Hellman
也是一种非对称的加密的方式,这种加密方式在密钥交换的过程(key exchange )中还蛮有做用呢。
数字证书(Digital Certificate)
一个小小的故事
密码学有三个名人 Alice, Bob和 Eve。 我们依然用他们三个来讲故事。
- Bob要给Alice发送一条信息, 为了证明这条信息是自己发的(没有被伪造 Authentication,没有被篡改 Integrity) 他将这条信息进行了签名并把签名和消息一起发给了Alice
- 拥有Bob公钥的Alice 得到这个消息和签名后 通过验证签名是否正确 确定这条消息确实是Bob发的 而且没有被篡改。
- 邪恶的Eve想伪造Bob,有一天他偷偷的潜入了Alice的电脑,并把Bob的公钥换成了自己的。物理攻击
- 这时Eve就可以伪装成Bob给Alice发消息, 并附带上一个用自己私钥加密后的摘要做签名。因为Alice还不知道Bob的公钥已经被换了,所以验证签名的过程会通过。 这时候Alice已经傻傻分不清Bob和Eve了。
这个问题说明只有公私钥对还是解决不了问题的。我们需要一个方法来保证公钥不会被篡改。又是一个Authentication(Ensure the users of the network are who they say they are)
的问题。 如果信任一个人,需要信任他的公钥, 然而如何做到公钥是可信的?(这里出现了肥皂距离的狗血剧情,既然你不相信我, 那你去问你信任的人好了。问一问他我说的是不是真的。)
后来Bob找到了Alice信任的人 — 一个叫CA的机构。 这个机构比较权威比较出名, 大家都知道他的公钥(因为所有人都知道所以没办法伪造)。 CA将Bob的公钥和Bob的名字以及其他信息放一个文件中,并用自己的私钥对这个文件进行签名,同时将签名放在这个文件的结尾,于是一个高大上的证书就生成了。
Alice 拿到 Bob 的证书后,首先用CA的公钥(这里实际上是一个自签名的根证书) 对Bob的证书进行完整性校验,确保确实是由CA颁发的。然后检查证书里面的信息确实是Bob, 这样 Alice就可以确信证书里面的公钥确实是Bob的公钥, 用他来验证Bob的信息没有问题。
上面的故事已经很好的解释了什么是数字证书及他的做用。 我们在介绍一下现实世界中的证书
现实世界中的证书
在公共网络中,首先有几个比较知名的大的CA机构比如VerSign他们会颁发根证书self-signed root certificate 我们的浏览器或者电脑会有一个信任根证书列表默认保存这些我们信任的根证书。 以MAC电脑为例, 默认信任列表长这样
为了保证根证书颁发机构密钥的安全性,他们会很吝啬的使用自己的密钥,但是有很多人需要去获得证书,肿么办? 于是CA只好去找几个有资质的机构,为他们颁发中间证书(Intermediate certificate authority),拥有这些中间证书的机构又能为自己信的过的机构颁发中间证书(Intermediate certificate authority) 这样就形成了证书链。
用户可以向任意一家CA去申请自己的证书。申请下来的证书长这样
可见www.dbbar.net
的域名证书是由CA 沃通免费SSL证书G2
颁发的。 这个CA机构也有自己的证书长这样
总结起来,现实世界按功能分为三种
- 自签名证书 self signed root certificate
- 为中间证书机构(intermediate certificate authority) 颁发的证书
- 为实际证书使用而颁发的证书
证书验证过程
写这篇文章的时候,我一直在想:既然信任链可以延续下去,那我们完全可以申请一个证书然后用这个证书来颁发其他的证书啊。 这样证书不就不可信了么。
猜想程序对证书的验证过程应该是这样的,首先从根证书到要验证证书的证书链。然后检查除要验证证书证书链以上的所有证书的类型是否是self signed root certificate 或者 intermediate certificate authority 如果不是,那么这个要验证的证书就验证不通过。
我们只能寄希望于所有的CA都是公开,公平,公正的了。他们会对每一个下级CA进行严格的审查, 以确保CA中不会有坏人。(万一哪天某动或者某通成了CA就不好说了,他们会直接伪造证书,进行中间人吧。)
HTTPS建立的过程
HTTPS 建立的前几秒主要是完成客户端对服务端的验证Authentication, 通信过程中用的加密方式,数据校验方式的协商, 通信过程中要使用的密钥(master key)的交换等过程。 因为后续的通信是加密的,可以防止监听(Confidentiality) 同时会进行数据的校验以防止内容被篡改(Integrity)
网上有好多介绍https的过程的,这里简单给一个时序图,感兴趣的同学可以去深入了解
解释:
Client Hello
这个包中有几个信息- Random,这里客户端给服务端发了第一个随机值为了方便我们叫做RandomA
- Session ID: 如果有的话服务端会决定是否要复用以前的session 以调过交换密钥的过程
- Cipher Suites:客户端支持的密码套件
- Extension: 一些扩展,比如server_name 用来标记要访问的
VHOST
以应对一个ip多个VHOST部署的情况。
Server Hello
这个包中返回了几个信息:- Random: 这是客户端给服务端的一个随机值我们计做RandomB
- Cipher Suite 要使用的密码套件
如
api.dbbar.net
返回的Server Hello
包长这样
这里可以看到Server端选用的加密套机是TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
(我们将在后文中解释Cipher Suite
)Server Certificate server端把证书发给client端
- Server Key Exchange
这一步与选择的加密套件有关, 有的加密套件规定的密钥协商机制需要每次动态的使用公钥和私钥。这一步骤传的Key需要用第3步传递的证书进行签名
如:
这里又涉及了另一个非对称加密算Difffie-Hellman
- * Server Hello Done *: Server Hello 结束
- Client Key Exchange: Client把自己的key发送给客户端, 这一步与选择的加密套件有关系。 总之,经过这一步骤之后客户端与服务端就会有一个共享的第三方不知道的密钥(
premaster
)。 然后客户端与服务端用这个密钥经过加密套件约定的密码推导算法推倒出用于通信的密钥master
- Change Cipher Spec从现在开始客户端用加密的方式与服务端通信
- Client Finished Message 客户端握手完成,发送的第一条加密信息
- New Session Ticket: 服务端给客户端发送一个ticket, 相当于新的session Id, 用于建立起来的信复用。
- Change Cipher Spec: 从现在开始服务端用加密的方式与服务端通信
- Server Finished Message: 服务端握手完成
一个比较直观的看ssl建立链接的过程是用openssl, 执行openssl s_client -debug -connect api.dbbar.net:443
或者采用wireshark抓包的方式会看到比较完整的连接建立信息这里不做赘述。
Cipher Suite
前面已经多次提到了cipher suite
究竟什么是cipher suite
? wiki上给的答案是 A cipher suite is a named combination of authentication, encryption, message authentication code (MAC) and key exchange algorithms used to negotiate the security settings for a network connection using the Transport Layer Security (TLS) / Secure Sockets Layer (SSL) network protocol. 简单的来说一个加密套件规定了TLS建立连接过程的具体细节如: 如何进行加密,如何产生信息校验码, 如何进行密钥交换。
一个Cipher Suite 比如我们前面提到的TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
定义了具体的密钥交换算法,块加密算法, 信息校验码产生算法, 及具体的密码推导算法 pseudorandom function(PRF)
在这个例子中
- 密钥交换算法:
ECDHE_RSA
定义了客户端与服务端如何进行premaster的传递。 - 块加密算法:
AES_256_CBC
是具体传递信息是用的块加密方法 - MAC: 这里用
SHA
的方式进行数据完整性校验 - Pseudo Random Function(PRF): PRF是TLS1.2 所有的密码推导算法。 这个算法采用伪随机数的生成的方式,以前面客户端与服务端端传递的
RandomA
,RandomB
,premaster
生成master key, 这个就是后续客户端与服务端通信要使用的密钥。用RandomA
,RandomB
来保证密钥的随机性不被任意一端所影响。 因为premaster交换的过程是保密的(第三方监听不到) 所以最终生成的master key也是保密的。
当然TLS协议定议了很多cipher suite, 每一个cipher suite 的安全性也不太一样,对CPU性能的占用也不太一样。
HTTPS下如何去抓包
HTTPS进行抓包,实际上是进行了一次中间人攻击。 我们需要伪造一个假的证书,并让客户端去信任这个证书。然后客户端与中间人就可以建立起TLS链接。然后中间人再去代理真正的客户端请求服务端。这样解决问题的方式就是这样的了:
那如何才能伪造假证书呢? 这时我们就需要在客户端安装一个我们知道密钥的根证书并信任它。这样我们就能用我们的密钥去颁发假的证书。而因为客户端信任了我们的根证书,所以它也会认为我们颁发的假证书是真正的证书, 这样真真假假就傻傻分不清楚了。
关于假证书的问题,记得前几年前goagent还存在的时候曾经报出个0 day 漏洞。因为好多人安装并信任了goagent的证书。并且goagent的证书的密钥是公开的。所以可以中间人攻击https服务。做法就是使用goagent的密钥来签名伪造的证书。这样屡试不爽。
我们以BurpSuite
为例,验证一下这个思路
HTTPS hacker
step1: 将Burpsuite的自签名证书导入firefox并信任。
step2: 设置firefox代理到burpsuite
我将用wareshare抓从firefox到burpsuite的包来分析流量
果然:这里用了一个我们之前信任的PortSwigger CA 证书签名了api.dbbar.net 域名。这样来实现中间人攻击。验证了之前的猜想
总结
- HTTPS本身还是比较复杂的。通过加密的方式,可以有效的防止中间人攻击,前提是客户端不要随意信任无效的证书。
- 面向HTTPS的协议有时需要去抓包分析,常用的抓包工具如
burpsuit
charlex
支持伪造证书以进行中间人攻击。 采用这种方式也方便了我们去分析HTTPS协议。