iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
0
Security

看完眼眶濕濕的App開發者慘烈對抗險惡資安環境血與淚的控訴!系列 第 28

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


上一篇
Day 27. 混血的最萌 - 混合加密系統(hybrid cryptosystem)
下一篇
Day 29. 手機螢幕截圖安全性問題,小心被看光光
系列文
看完眼眶濕濕的App開發者慘烈對抗險惡資安環境血與淚的控訴!31

尚未有邦友留言

立即登入留言