Day 28. 凭证绑定 Certificate Pinning 绑起来!

今天来介绍,数位凭证,讲一点点数位签章,以及最重要的凭证绑定原理及用途

避免有人透过手机使用 Burp Suite 或 Charles 拦截,即可发现凭证内容不符合,而拒绝连线进而达到保护的目的

image-20201013004032087

凭证是什麽?

一般我们在说的网页用凭证 SSL / TLS 凭证,也称为 数位凭证(digital certificate)用来证明公开金钥拥有者的身分。

此档案包含了公钥资讯、拥有者身分资讯(主体)、以及数位凭证认证机构(发行者)

且对这份档案做了数位签章,确保档案内容正常没有问题

数位签章(英语:Digital Signature,又称公钥数位签章)

数位签章是能够实现『身分鉴别』和『检查讯息完整性』两种功能的讯息鉴别码 外也加入了不可抵赖性机制

作法可看前面的『讯息鉴别码』章节,加密流程相同,差别采用公开金钥机制,因此可以确定讯息的制作者

数位凭证就是用来确保使用者使用的服务器凭证是服务器提供的

凭证申请

为了确保是咩的公钥,需要跟凭证机构(certification authority) CA 申请发行凭证证明金钥 P咩 是咩的

image-20201013134145964

凭证机构机构本身也具有自己的公开金钥PCa 及私密金钥Sca

接下来 咩 将自己的,个人资讯加上公开金钥,传送给凭证机构

image-20201013134447226

凭证机构确认过资讯後,使用凭证机构的 私密金钥 Sca 进行签章

image-20201013134917646

凭证机构将制作完成的数位签章跟数据合成一个电子档

image-20201013135025068

最後凭证机构把电子档案传回给 咩,这个电子档就是咩的数位凭证

image-20201013135226124

咩接着就可以传送自己的数位凭证,取代只有传送公钥

检查凭证有效

使用者/客户端进行动作确认凭证有效

  • 验证数位凭证的根凭证(Root Certificate),再自己的系统凭证中存不存在有相同的根凭证
  • 从 CA 取出CA公钥,用来验证凭证内签名,确保一致,代表此数位凭证是该 CA 提供
  • 验证凭证内的资讯,是否与现况批配,网址,姓名,email .....等等

凭证用途非常的广,国人使用的自然人凭证,工商凭证,健保卡等都是属於数位凭证的用途

另外我们使用再服务器尚的数位凭证又称为『服务器凭证』、HTTPS/SSL凭证

看看一个例子

下图为维基百科的凭证(数位凭证)

截图 2020-10-13 上午10.54.33

得知以下资讯

  • 主体
    • 名称:*.wikipedia.org
  • 签发单位
    • 公司:Let's Encrypt
    • 指纹:04 A3 4E 15 E5 F9 7A 31 14 D1 E3 CB 80 78 DD CF 0A B6
    • 演算法:RSA加密的SHA-256
  • 公钥资讯:
    • 演算法:椭圆曲线公用密钥
    • 参数:椭圆曲线secp256r1
    • 金钥:65 byte : 04 05 79 47 ......
  • 指纹
    • sha-256 :1C 85 CA 58 CE 9 ....
  • 根凭证
    • 名称:DST Root CA

可以整理出 wikipedia.org 网域,使用 ecc - secp256r1 公钥 ,并且透过 Let's Encrypt 将这些资讯进行签章

为什麽要凭证绑定

当我们已经使用数位凭证再我们的Server上为什麽还需要凭证?

因为原本方式只能确保服务器的公钥是服务器原始提供的

并无法确认,客户端/使用者是否有进行凭证的验证

先前的章节提过我们可以使用公开金钥系统对资料进行保护,看起来万无一失,但黑客却不直接对演算法进行攻击,而是使用窃听(eavesdrop)和电子欺骗(spoofing)方式进行伪装

这方式又称为 中间人攻击(Man-in-the-middle attack,MITM)

取代掉原本的数位凭证,使用者端若是没有进行验证将会被劫持传输的内容

image-20201013113922350

在处理方式上,普遍是使用凭证绑定 (certificate pinning) 的方式,把需要比对的凭证预先存放在应用程序里,等要进行 SSL Handshake 的时候再与服务器的凭证做比对。

当遇到有被取代掉的凭证,使用者用了 Burp Suite 或 Charles 想要拦截流量,由於凭证会更换为Burp或Charles

我们APP再进行连线时,即可发现凭证内容不符合,而拒绝连线进而达到保护的目的

凭证绑定 Certificate Pinning

iOS

import Alamofire
//自定 manager
fileprivate static var manager: Alamofire.SessionManager = {

    // Create custom manager
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    return Alamofire.SessionManager(
        configuration: configuration,
        serverTrustPolicyManager: CustomServerTrustPoliceManager()
    )
}()

class CustomServerTrustPoliceManager : ServerTrustPolicyManager {
    //自订信任协议
    override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
        //如果网域符合
        if host.hasSuffix("www.example.com") {
						//从档案资料夹取出凭证
            let dir_bundle:Bundle = Bundle.init(path: "/certificates")!           
            let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
                //进行比对的参数
                certificates: ServerTrustPolicy.certificates(in:dir_bundle),
                validateCertificateChain: true,
                validateHost: true
            )
            return serverTrustPolicy
        }
        return .performDefaultEvaluation(validateHost: true)
    }
    public init() {    
        super.init(policies: [:])
    }
}

Android

Android 新的OS 可以使用网络安全配置 功能,可以直接使用此功能定义网路安全设定,而无需使用程序码

透过 进行设定

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

或是使用程序码的方式,将金钥放入KeyStore,再连线的时候进行比对

KeyStore keyStore = ...;
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);

SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();

WebView 内连线可以做凭证绑定吗?

Android 跟 iOS 系统本身内无法直接像 Http 请求可以直接设定凭证绑定验证

但可以自己实作,可以拦截请求连线,改成自己定义Http连线,并检查凭证是否有检验通过

参考资料

https://developer.android.com/training/articles/security-config.html#CertificatePinning

https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning

https://devco.re/blog/2014/08/15/ssl-mishandling-on-mobile-app-development/

https://developer.android.com/training/articles/security-ssl.html#UnknownCa


<<:  寻觅 webpack - 28 - 真实世界的 webpack - 配置多模式专案

>>:  2020it邦铁人赛-30天手把手的Vue.js教学 Day30 - 关心时事! 做个简单的COVID-19追踪app吧!(下)

MyBatis 前导

MyBatis前导 ...

Day 15:RecyclerView 卡片式项目布局

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

Day 10 运算宝石:EC2 储存资源 Instance Store vs Elastic Block Storage (EBS)

现在我们来介绍 EC2 里面的 Instance Storage 与 EBS 的差别,那我们开始吧...

Day17 参加职训(机器学习与资料分析工程师培训班),Python程序设计

练习使用selenium来登入FB from selenium import webdriver d...

Day15 - 中场休息时间 - 来看看htmlToCanvas的实作吧 - 成为Canvas Ninja ~ 理解2D渲染的精髓

经过了连续5篇复杂度略高的物理模拟系列,我在想看官们多少会有点疲乏~ 所以我在规划了几篇『中场休息』...