1. 准备知识
如果需要明白SSL/TLS的工作原理,首先需要明白HTTPS的工作原理,它和HTTP之间的区别是什么?
1.1 HTTP的介绍
HTTP(超文本传输协议)被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
1.2 HTTPS的介绍
HTTPS(安全套接字层超文本传输协议),解决了HTTP的这一缺陷。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL/TLS协议,SSL/TLS依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。 HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比HTTP协议安全 HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
1.3 HTTP和HTTPS的主要区别
- HTTPS协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
- HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的ssl/tls加密传输协议。
- HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- HTTP的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。
2. SSL/TLS
2.1 SSL/TLS历史
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的修订版,在2018年也发布了TLS1.3版本。 TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。 目前应用的最广泛的 TLS 是 1.2,而之前的协议(TLS1.1/1.0、SSLv3/v2)都已经被认为是不安全的了。
2.2 SSL/TLS协议基本过程(TLS1.2)
- 客户端向服务器端索要并验证公钥。
- 双方协商生成"对话密钥"。
- 双方采用"对话密钥"进行加密通信。
2.3 SSL/TLS协议详细过程(TLS1.2)
如果不做深入研究,可以跳过本小节
- 客户端发出请求(ClientHello)
(1) 支持的协议版本,比如TLS 1.2版。 (2) 一个客户端生成的随机数1,稍后用于生成"对话密钥"。 (3) 【支持的密码套件】支持的加密方法,比如RSA公钥加密。 (4) 支持的压缩方法。 (5) 一个session id,标识是否复用服务器之前的tls连接(需要服务器支持) - 服务器回应(SeverHello)
(1) 确认使用的加密通信协议版本,比如TLS 1.2版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。 (2) 一个服务器生成的随机数2,稍后用于生成"对话密钥"。 (3) 【确认密码套件】确认使用的加密方法,比如RSA公钥加密,此时带有公钥信息。 (4) 一个session id(若同意复用连接) - 服务器回应(Server Certificate)
(1)服务器证书(该证书即包含服务器公钥)。 - 服务器回应(Server Key Exchange)
(1)服务器算法变更通知,服务端给客户端一个用于 ECDHE 算法的公钥 - 服务器回应(Server CertificateRequest)
(1)请求客户端证书,一般银行等需要客户端也加密的才有,比如 U 盾。 - 服务器回应(Server ServerHelloDone)- 标识着 serverHello 这个握手过程结束了。
- 客户端回应(Client Certificate)- 回应客户端证书
- 客户端回应(ClientKeyExchange)
(1)客户端在验证完服务器的证书后,生成一个新的随机数(pre_master),通过服务器的公钥加密后发给服务器。 到这里,服务端与客户端将 生成最终通信的对称加密秘钥:master_secret 计算过程根据上面得到的三个随机数: 随机数 1(客户端随机数):在 ClientHello 消息里,由客户端生成的随机数1 随机数 2(服务端随机数):在 ServerHello 消息里,由服务端生成的随机数2 随机数 3(pre_master):通过秘钥交换算法 ECDHE 计算出的,我们叫它 pre_master。 最终的对称加密秘钥 master_secret,就是根据这三个随机数共同计算出来的。 - 客户端回应(Client CertificateVerif)
(1)验证客户端证书有效性,本次不涉及 - 客户端回应(Client ChangeCipherSpec)
(1)秘钥改变通知,此时客户端已经生成了 master_secret,之后的消息将都通过 master secret 来加密。 - 客户端回应(Client Finish)
(1) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。 - 服务器回应(Server ChangeCipherSpec)
(1)秘钥改变通知,此时服务端也已经生成了 master_secret 了,后面的通信都用此值加密。 - 服务器回应(Server Finish)
(1)同 Client Finish,服务器端发送握手结束通知,同时会带上前面所发内容的hash签名到客户端,保证前面通信数据的正确性。
上述流程简易版(不包含验证客户端证书):
- client --> server ClientHello
客户端生成随机数,并发送一组密码学套件供服务端选 - server–> client ServerHello
服务端生成随机数,并从上述密码学套件组里选一个 - server–> client Certificate
服务端发给客户端证书 - server–> client ServerKeyExchange
服务端发给客户端秘钥交换算法所需的值 - server–> client ServerHelloDone
服务端 hello 阶段结束 - client --> server ClientKeyExchange
客户端发给服务端秘钥交换算法所需的值pre_master - client --> server ChangeCipherSpec
客户端告诉服务端,我已经知道秘钥了,之后的消息我就都加密发送了。 - client --> server Finish
结束并验证 - server --> server ChangeCipherSpec
服务端告诉客户端,我已经知道秘钥了,之后的消息我就都加密发送了。 - server–> client Finish
结束并验证
2.4 HTTPS的缺点
HTTPS很安全,很古老也很成熟,为什么一直到今天我们还有66%的网站不支持HTTPS呢?
- 慢,HTTPS未经任何优化的情况下要比HTTP慢几百毫秒以上,特别在移动端可能要慢500毫秒以上,关于HTTPS慢和如何优化已经是一个非常系统和复杂的话题
- 贵,特别在计算性能和服务器成本方面。HTTPS为什么会增加服务器的成本?相信大家也都清楚HTTPS要额外计算,要频繁地做加密和解密操作,几乎每一个字节都需要做加解密,这就产生了服务器成本
- 大量的计算。SSL的每一个字节都涉及到较为复杂的计算。即使是clientHello,也需要在握手完成时做校验。
- TLS协议的封装和解析。HTTPS所有数据都是按照TLS record格式进行封装和解析的。
- 协议的网络交互。从TLS的握手过程可以看出,即使不需要进行任何计算,TLS的握手也需要至少1个RTT(round trip time)以上的网络交互。
RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。
- HTTPS降低用户访问速度(需多次握手)
- 网站改用 HTTPS 以后,由 HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用 301、302 跳转)
- HTTPS 涉及到的安全算法会消耗 CPU 资源,需要增加服务器资源(https 访问过程需要加解密)
3. SSL/TLS Pinning
3.1 概述
证书锁定(SSL/TLS Pinning)顾名思义,将服务器提供的SSL/TLS证书内置到移动端开发的APP客户端中,当客户端发起请求时,通过比对内置的证书和服务器端证书的内容,以确定这个连接的合法性。
3.2 预备知识
- 可信CA:CA(Certificate Authority)是数字证书认证中心的简称,是指发放、管理、废除数字证书的机构.CA的作用是检查证书持有者身份的合法性,并签发证书,以防证书被伪造或篡改,以及对证书和密钥进行管理。
- 双向锁定
在客户端锁定服务端证书的基础上,服务端对客户端的证书也进行锁定,需要客户端再做一次证书预埋.多见于金融业务。 - 证书链
证书链就是Root CA签发二级Intermediate CA,二级Intermediate CA可以签发三级Intermediate CA,也可以直接签发用户证书.从Root CA到用户证书之间构成了一个信任链:信任Root CA,就应该信任它所信任的二级Intermediate CA,从而就应该信任三级Intermediate CA直至信任用户证书。 - 逐级验证
客户端对于收到的多级证书,需要从站点证书(leaf certificate)开始逐级验证, 直至出现操作系统或浏览器内置的受信任CA 根证书(root certificate)。
通常逐级检测点如下:
- 是否由上级证书签发
- 是否吊销
- 是否过期
- 是否遵循上级证书的策略
3.3 原理
证书锁定(SSL/TLS Pinning)提供了两种锁定方式: Certificate Pinning 和 Public Key Pinning。
- 证书锁定
我们需要将APP代码内置仅接受指定域名的证书,而不接受操作系统或浏览器内置的CA根证书对应的任何证书,通过这种授权方式,保障了APP与服务端通信的唯一性和安全性,因此我们移动端APP与服务端(例如API网关)之间的通信是可以保证绝对安全。但是CA签发证书都存在有效期问题,所以缺点是在证书续期后需要将证书重新内置到APP中。 - 公钥锁定
公钥锁定则是提取证书中的公钥并内置到移动端APP中,通过与服务器对比公钥值来验证连接的合法性,我们在制作证书密钥时,公钥在证书的续期前后都可以保持不变(即密钥对不变),所以可以避免证书有效期问题。
3.3 证书锁定的收益
安全性提升,更加有效覆盖对抗中间人攻击场景。 证书锁定本质是对抗中间人攻击.并非用于对抗破解抓包的.但如果程序逻辑未被注入运行在"可信环境"中倒是有些作用。
- SSL对抗的攻击场景:
中间人攻击部分场景 ARP欺骗 DNS劫持 钓鱼WIFI 伪基站 - ssl pinning新增对抗场景:
客户端安装恶意证书 一些WiFi需要你添加根证书信任才能使用互联网 其他CA恶意签发站点证书
4. Android SSL证书设置和锁定
https://zhuanlan.zhihu.com/p/127847550
我们认识到在移动端开发中安全性设置非常重要,尤其是目前非常流程H5混合式开发APP,在Android开发中,我们可以通过证书锁定的方式来增加客户端与服务端的安全保障
4.1 HttpsURLConnection SSL pinning
使用传统的HttpURLConnection类封装请求,客户端锁定操作需要实现X509TrustManager接口的checkServerTrusted方法,通过对比预埋证书信息与请求网站的的证书来判断。
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
if (cache.contains(chain[0])) {
return;
}
checkSystemTrust(chain, authType);
checkPinTrust(chain);
cache.add(chain[0]);
}
4.2 OkHttp SSL pinning
okhttp将锁定操作封装的更人性化,你只要在client build时加入域名和证书hash即可。okhttp3.x 锁定证书示例代码。
String hostname = "yourdomain.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
client.newCall(request).execute();
5. iOS SSL证书设置和锁定
6. Andorid证书认定的解除
https://github.com/WooyunDota/DroidSSLUnpinning
6.1 针对HttpsURLConnection
注入SSLContext的init方法替换信任所有证书的TrustManger
var SSLContext_init = SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
quiet_send('Overriding SSLContext.init() with the custom TrustManager');
SSLContext_init.call(this, null, TrustManagers, null);
};
6.2 针对OkHttp
frida Unpinning script for okhttp
setTimeout(function(){
Java.perform(function () {
try {
var CertificatePinner = Java.use("okhttp3.CertificatePinner");
CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(p0, p1){
console.log("Called! [Certificate]");
return;
};
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(p0, p1){
console.log("Called! [List]");
return;
};
} catch (e) {
console.log("okhttp3 not found");
}
try {
var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient");
OkHttpClient.setCertificatePinner.implementation = function(certificatePinner){
console.log("Called!");
return this;
};
var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");
CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(p0, p1){
console.log("Called! [Certificate]");
return;
};
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(p0, p1){
console.log("Called! [List]");
return;
};
} catch (e) {
console.log("okhttp not found");
}
});
},0);
6.3 官方推荐的方案
https://developer.android.com/preview/features/security-config.html
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>
</manifest>
- 自定义可信CA
假设您要连接到使用自签名 SSL 证书的主机,或者连接到其 SSL 证书由您信任的非公共 CA(如公司的内部 CA)颁发的主机。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<certificates src="@raw/my_ca"/>
</trust-anchors>
</domain-config>
</network-security-config>
其他配置可见官方文档,不再赘述。
|