伯阳的网络笔记:HTTPS 概述
伯阳的网络笔记(七):HTTPS
因为疫情期间在外当志愿者,晚上回家无聊翻翻网络知识,权当记录了。
初始动笔:2019-03-03
修改时间:2019-04-02
1. HTTPS
简单的说,HTTPS == HTTP + TLS。在 HTTP 层下面, TCP 层上面,加入了一个 TLS 层用于加密。
关于 TLS 握手,可以查看上一篇文章。
HTTPS 采用混合的加密机制,使用公开密钥加密用于传输对称密钥,之后使用对称密钥加密进行通信。
2. 证书
Certification Authority,简称 CA,证书颁发机构,是指我们都信任的证书颁发机构。
我们在使用 HTTPS 之前,需要向 CA 申请一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”。
证书在 TLS 握手过程中可以直接的进行操作。
3. 中间人攻击
中间人攻击是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
简单的说,就是存在攻击者在请求和响应传输途中,拦截并篡改内容。
我们知道 HTTPS 在最开始会进行 TLS 握手过程,而中间人攻击一般是发生在会话建立之前。
一般是如下的流程:
第一步
中间人拦截客户端的 Client Hello ,获取其中的随机数,然后继续发送 Client Hello 给服务器;
第二步
服务器发出 Server Hello、Certificate、Server Key Exchange、Server Hello Done,中间人收到消息,并保存;
第三步
中间人发送 ClientCertificate、 ClientKeyExchange 、ChangeCipherSpec、Finished。
发送 ClientCertificate,携带真实的客户端证书,可以在 Charles 的 SSL Proxying Setting 里的 Client Certificate 里配置;
发送 ClientKeyExchange ,携带伪造的 Client DH 协商参数;和服务器协商出预主密钥,计算出主密钥1;发送 ChangeCipherSpec ,通知服务器更改密码规范,发送 Finished 验证密钥。
第四步
中间人收到服务器的 Finished 。 收到服务器的 Finished 以后,发送 ServerHello 给客户端,携带伪造的服务器随机数; 发送 ServerCertificate ,携带伪造的服务器证书; 发送 ServerKeyExchange ,携带伪造的服务器 DH 协商参数; 发送 CertificateRequest ,请求客户端证书; 发送 ServerHelloDone ,问候结束。
4. 如何防止中间人攻击
如何防止中间人攻击的,其实也就是如何解决信任的问题,客户端如何判断出是真实的服务器还是中间人呢?
域名强校验
自定义证书验证逻辑,收到Server Certificate,校验证书域名。这是比较初级的保护手段,对于一般的攻击来说明没有什么作用。
SSL Pinning
加密固定技术,包含两种实现:
-
Certificate Pinning:
证书固定,也就是把服务器证书固定在客户端里,每一次请求收到服务器证书的时候,对比证书是否一致,一致则认为是安全的,否则认为是不安全的。这种方式有个很大的问题,就是证书如果如果更新了,那么客户端必须同步更新证书,需要强升,否则不能使用。
-
Certificate Public Key Pinning
证书公钥固定,原理类似,只不过是把服务器证书的公钥固定在客户端,每一次请求收到服务器证书的时候,对比证书的公钥是否一致。尽管服务器证书更新了,依然可以保持公钥不变,所以不受影响。而且现在一般原生 App 都是配置多个公钥,完全可以应对证书替换的情况,所以是现在比较流行的解决方案,而且现在移动端的网络框架基本都支持,比如说 OKHttp、AFNetworking、Alamofire 等等。
双向认证
SSL/TLS 本身支持双向认证,即服务端需要校验客户端证书,服务端存储了签发客户端证书的根证书,客户端证书需要预先内置在原生 App 里,每次请求服务端都会请求客户端证书,来验证是否是收信任的客户端。其实和网银U盾的原理类似。
这种方案使用场景有限,适合隐私性比较强的应用。而且也不能完全避免中间人攻击,现在Charles等等工具都支持设置Client Certificate了,可以在握手的时候,中间人传输设置好的客户端证书给服务器。
数字签名
最后我们说一下数字签名,数字签名是只有消息的发送者才能产生一段字符串,别人无法伪造(除非知知道你的签名算法),这段字符串也是对发送的消息的完整性的一个校验。
防止 Hook
攻击者完全逆向原生 App,在二进制包 Headers 里的Load Command 加入自己的动态库,通过 Hook 的方式,直接 Hook 掉校验 API 和签名的 API ,无论是 Android 还是 iOS ,越狱非越狱,都可以破解。
对于 iOS 开发来说,我们可以检测二进制文件Headers里的LoadCommands是否包含异常的库。
5. 性能损耗
未完待续