• 【网络安全】SSL Pinning及其绕过


    SSL Pinning

    1 HTTPS协议流程

    参考:
    https://segmentfault.com/a/1190000009002353?sort=newest
    https://zhuanlan.zhihu.com/p/353571366

    HTTPS=HTTP+TLS,其它的协议也类似,如FTPS=FTP+TLS
    在这里插入图片描述
    1) ClientHello

    • Client 首先发送本地的 TLS 版本、支持的加密算法套件,并且生成一个随机数 R1 。

    2)Server Hello

    • Server 端确认 TLS 版本号。从 Client 端支持的加密套件中选取一个,并生成一个随机数 R2 一起发送给 Client。
    • Server 向 Client 发送自己的CA证书(包含公钥、证书签名)。

    3)证书校验

    • Client 判断证书签名与CA证书是否合法有效
    • Client 生成随机数pre-master secret,并使用Server发过来的公钥对pre-master secret进行加密,将加密后的pre-master secret送给Server。这一步结束后,Client 与 Server 就都有 R1、R2、pre-master secret 了,两端便可以使用这 3 个随机数独立生成 对称会话密钥了,避免了对称密钥的传输,同时可以根据会话密钥生成 6 个密钥(P1~P6)用作后续身份验证

    Client端和Server端,最终都会用相同的算法将pre-master secret(预主密钥)转换成master secret(主密钥),通过主密钥可以生成session key。两者后续的通信交互数据,将通过session key进行加密。
    在这里插入图片描述
    参考:https://www.laoqingcai.com/tls1.2-premasterkey/

    4)Client 握手结束通知

    • Client 使用 P1 将之前的握手信息的 hash 值加密并发送给 Server
    • Client 发送握手结束消息

    5)Server 握手结束通知

    • Server 计算之前的握手信息的 hash 值,并与 P1 解密客户端发送的握手信息的 hash 对比校验
    • 验证通过后,使用 P2 将之前的握手信息的 hash 值加密并发送给 Client

    6)Client 开始HTTPS通讯

    • Client 计算之前的握手信息的 hash 值,并与 P2 解密 Server 发送的握手信息的 hash 对比校验
    • 验证通过后,开始发起 HTTPS 请求。

    两者后续的通信交互数据,将通过session key进行加密。所以中间人即使截获数据,也无法解析。

    2 证书相关

    证书文件

    证书=服务器公钥+(服务器公钥+服务器信息)的签名

    图片名称

    CA

    签名=摘要+私钥加密
    CA:Certificate Authority,专门用自己的私钥 给别人进行签名的机构

    证书的验证过程

    关键过程:用信任CA库里CA证书(公钥),验证网站的证书文件里的签名

    1. 在TLS握手的过程中,客户端得到了网站的证书
    2. 客户端打开证书,查看是哪个CA签名的这个证书
    3. 在自己信任的CA库中,找相应CA的证书(包含CA的公钥),
    4. CA证书里面的公钥解密网站证书上的签名,取出网站证书的摘要,然后用同样的算法(比如sha256)算出网站证书的摘要,如果摘要和签名中的摘要对的上,说明这个证书是合法的,且没被人篡改过
    5. 读出里面的CN,对于网站的证书,里面一般包含的是域名
    6. 检查里面的域名和自己访问网站的域名对不对的上,对的上,就说明这个证书确实是颁发给这个网站的
    7. 到此为止检查通过

    3 SSL Pinning

    参考:
    https://shunix.com/ssl-pinning/
    https://zhuanlan.zhihu.com/p/58204817

    SSL Pinning可以分为Certificate Pinning(证书锁定)和Public Key Pinning(公钥锁定)

    3.1 证书锁定

    把证书文件打包进安装包,将app设置为仅接受指定的内置证书,而不接受操作系统内置的CA根证书对应的任何证书。

    3.2 公钥锁定

    提取证书中的公钥并内置到App中,通过与服务器对比公钥值,来验证连接的合法性。我们在申请证书时,公钥在证书的续期前后可以保持不变,所以可以解决证书有效期问题。

    3.3 证书锁定实例:基于TrustManagerFactory

    // kotlin语法
    
    // 加载证书文件
    val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
    val caInput: InputStream = BufferedInputStream(FileInputStream("load-der.crt"))
    
    // 使用CertificateFactory生成一个X509Certificate的实例
    val ca: X509Certificate = caInput.use {
        cf.generateCertificate(it) as X509Certificate
    }
    System.out.println("ca=" + ca.subjectDN)
    
    
    // 创建一个KeyStore实例,并把前边的X509Certificate实例加进去,并起一个别名"ca"
    val keyStoreType = KeyStore.getDefaultType()
    val keyStore = KeyStore.getInstance(keyStoreType).apply {
        load(null, null)
        setCertificateEntry("ca", ca)
    }
    
    // 创建一个TrustManagerFactory实例,并且使用前边的KeyStore实例进行初始化
    val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
    val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
        init(keyStore)
    }
    
    // 创建一个SSLContext实例,并且使用前面的TrustManagerFactory实例的trustManagers进行初始化
    val context: SSLContext = SSLContext.getInstance("TLS").apply {
        init(null, tmf.trustManagers, null)
    }
    
    // 创建HttpsURLConnection实例urlConnection
    val url = URL("https://certs.cac.washington.edu/CAtest/")
    val urlConnection = url.openConnection() as HttpsURLConnection
    
    // 将SSLContext实例context的socketFactory属性,赋值给urlConnection
    urlConnection.sslSocketFactory = context.socketFactory
    
    val inputStream: InputStream = urlConnection.inputStream
    copyInputStreamToOutputStream(inputStream, System.out)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3.4 证书锁定实例:基于配置文件

    需要在Manifest文件的android:networkSecurityConfig属性加上对应的配置内容,示例如下:

    
    <network-security-config>
    	
        <domain-config>
            <domain includeSubdomains="true">example.comdomain>
            <trust-anchors>
                <certificates src="@raw/my_ca"/>
            trust-anchors>
        domain-config>
        
        
        <domain-config>
            <domain includeSubdomains="true">example.comdomain>
            <pin-set expiration="2018-01-01">
                <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=pin>
                
                <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=pin>
            pin-set>
        domain-config>
    network-security-config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    华为机试真题 C++ 实现【统计文本数量】
    湖南旅游市场游客满意度调查报告
    ARP欺骗攻击
    Kolla-ansible部署openStack
    service workers跟页面dom交互
    什么是Helm?它是如何提升云原生应用私有化部署效率的
    算法设计 - 分治法
    Node.js -- http模块
    elementPlus的table设置序号
    呕心沥血 JavaScript知识点梳理大全,超详细 建议收藏!!!
  • 原文地址:https://blog.csdn.net/qq_39441603/article/details/126183031