SSL證書(shū)驗(yàn)證
?一種加強(qiáng)App 和 Server 間通訊安全的方法。主要目標(biāo)是確保 App 僅與預(yù)先驗(yàn)證的 Server 建立安全連接,防止中間人攻擊(Man-in-the-Middle,MitM)等安全風(fēng)險(xiǎn)。一般常用的有兩種方式進(jìn)行驗(yàn)證,Certificate Pinning和Public Key Pinning。
Alamofire5.0 以后將證書(shū)驗(yàn)證類放于ServerTrustEvaluation這個(gè)類里面。一共有6種驗(yàn)證策略:
- DefaultTrustEvaluator - (默認(rèn)驗(yàn)證策略)只要是合法證書(shū)就能通過(guò)驗(yàn)證。
- RevocationTrustEvaluator(驗(yàn)證注銷策略)對(duì)注銷證書(shū)做的一種額外設(shè)置,Alamofire從iOS10.1才開(kāi)始支持吊銷證書(shū)的策略。
- PinnedCertificatesTrustEvaluator(證書(shū)驗(yàn)證策略)app端會(huì)對(duì)服務(wù)器端返回的證書(shū)和本地保存的證書(shū)中的全部?jī)?nèi)容進(jìn)行校驗(yàn)需要全部正確,此驗(yàn)證策略還可以接受自簽名證書(shū),安全性相對(duì)較高,此方法較為固定,如果 Server 更新證書(shū),App 需要定期更新并重新上架。
- PublicKeysTrustEvaluator(公鑰驗(yàn)證策略)app端只會(huì)對(duì)服務(wù)器返回的證書(shū)和本地保存的證書(shū)中的 PublicKey(公鑰)進(jìn)行校驗(yàn),所以當(dāng)證書(shū)需要更新時(shí),只需確保公鑰保持不變,不需要更新App。
- CompositeTrustEvaluator(自定義組合驗(yàn)證策略)以上多種策略組合一起,只有在所有數(shù)組中值都成功時(shí)才成功。
- DisabledTrustEvalutor(不驗(yàn)驗(yàn)證策略)無(wú)條件信任,所有都可以通過(guò)驗(yàn)證。正式環(huán)境不建議用此策略,多用于測(cè)試。
我們用的是PublicKeysTrustEvaluator(公鑰驗(yàn)證策略)
1.后臺(tái)提供證書(shū),將正式放在項(xiàng)目目錄中。

本地證書(shū)存放
2.獲取本地證書(shū),提取證書(shū)的公鑰(獲取公鑰key數(shù)組)。證書(shū)后綴名一般有:.cer、.crt、.der等,我項(xiàng)目中用的cer,證書(shū)鏈必須包含一個(gè)固定的公鑰。
struct WTCertificates {
static let rootCA = WTCertificates.certificate( )
static func certificate() -> [SecKey] {
var publicKeyArray:[SecKey] = []
for resource in ["xxx", "xxxx", "xxxxx"] {// 本地證書(shū)名稱
if let filePath = Bundle.main.path(forResource: resource, ofType: "cer"), let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)) as CFData, let certificate = SecCertificateCreateWithData(nil, data),let publicKey = certificate.af.publicKey {
publicKeyArray.append(publicKey)
}
}
return publicKeyArray
}
}
3.給Session添加策略(接受質(zhì)詢)
var requestManagerSession: Session = {
if WTCertificates.rootCA.count > 0, verifyCert {
let certificates: [SecKey] = WTCertificates.rootCA
let trustPolicy = PublicKeysTrustEvaluator(keys: certificates, performDefaultValidation: false, validateHost: false)
let manager = ServerTrustManager(evaluators: [
"xxx.xxx.com": trustPolicy,
"xx.xx.jftplus.com": trustPolicy,
"xxx.xx.com": trustPolicy])// base url 如何域名過(guò)多,可以子類化 ServerTrustManager,并用自己的自定義實(shí)現(xiàn)重寫(xiě) serverTrustEvaluator(forHost:) 方法
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}
return MoyaProvider<ApiManager>.defaultAlamofireSession()
}()
4.在Moya中添加requestManagerSession
var JKOtherApiManagerProvider = MoyaProvider<JKOtherApiManager>(endpointClosure: endpointMapping, requestClosure: requestTimeoutClosure, session:requestManagerSession, plugins:[RequestAlertPlugin(), networkPlugin])
OC HTTPS 證書(shū)配置驗(yàn)證
//1 將證書(shū)拖進(jìn)項(xiàng)目
//2 獲取證書(shū)路徑
NSString *certPath = [[NSBundle mainBundle] pathForResource: @"cetus" ofType:@"cer"];
//3 獲取證書(shū)data
NSData *certData = [NSData dataWithContentsOfFile:certPath];
//4 創(chuàng)建AFN 中的securityPolicy
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:[[NSSet alloc] initWithObjects:certData,nil]];
//5 這里就可以添加多個(gè)server證書(shū)
NSSet *dataSet = [[NSSet alloc]initWithObjects:certData, nil];
//6 綁定證書(shū)(不止一個(gè)證書(shū))
[securityPolicy setPinnedCertificates:dataSet];
//7 是否允許無(wú)效證書(shū)
securityPolicy.allowInvalidCertificates = YES;
//8 是否需要驗(yàn)證域名
securityPolicy.validatesDomainName = YES;
uploadManager.securityPolicy = securityPolicy;
我們后臺(tái)給的證書(shū)格式后綴是.pem,以下是用OpenSSL命令將.pem證書(shū)轉(zhuǎn)換為cer格式證書(shū)方法
- 打開(kāi)命令行工具,進(jìn)入存放xxx.pem證書(shū)的目錄
- 輸入以下命令,將.pem證書(shū)轉(zhuǎn)換為cer格式
openssl x509 -in xxx.pem -inform PEM -out xxx.cer -outform DER
- 執(zhí)行完畢后,您將在當(dāng)前目錄下看到生成的xxx.cer文件
注意:轉(zhuǎn)換后的cer證書(shū)文件只包含公鑰,不包含私鑰信息