Edited at

MITM対策にSwift4でCertificate Pinningをやってみた

More than 1 year has passed since last update.


はじめに

iOSアプリケーションの安全性を上げるために、MITM対策をCertificate Pinningをやってみました。

MITMやSSLとは?という方は下記のWikipediaを参考にしてください。

MITM SSL/TLS


環境

・Xcode 9.3

・Swift 4.1

・macOS 10.3


実装

通信を行うクラスにURLSessionDelegateを継承してください。

継承したクラスに下記のurlSessionメソッドを追加してください。

func urlSession(_ session: URLSession, didReceive challenge:URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

let serverTrust = challenge.protectionSpace.serverTrust
let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)

//ドメイン名を確認するpoliciesにSSLをセットする
let policies = NSMutableArray()
policies.add(SecPolicyCreateSSL(true, (challenge.protectionSpace.host as CFString)))
SecTrustSetPolicies(serverTrust!, policies)

//SSL証明書をチェックする
var result: SecTrustResultType = SecTrustResultType(rawValue: 0)!
SecTrustEvaluate(serverTrust!, &result)
let isServerTrusted:Bool = result == SecTrustResultType.unspecified || result == SecTrustResultType.proceed

//ローカルとリモートの証明書データを取得する
let remoteCertificateData:NSData = SecCertificateCopyData(certificate!)
//○○○に証明書ファイル名、□□□に型名を入れる
let pathToCert = Bundle.main.path(forResource: "○○○", ofType: "□□□")

let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!

if (isServerTrusted && remoteCertificateData.isEqual(to: localCertificate as Data)) {
let credential:URLCredential = URLCredential(trust: serverTrust!)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}

これで基本的な実装は終了です。

後はこのようにすれば完成です。

  let configuration = URLSessionConfiguration.default

let session = URLSession(configuration: configuration, delegate: self, delegateQueue:OperationQueue.main)
var request = URLRequest(url:url)
let task = session.dataTask(with: request) { data, response, error in
//処理を書く
}

実行確認はこちら等を参考に

Charlesで他社アプリの通信を覗く


参考

Certificate pinning technique on iOS