四抛猫、Security部分
顧名思義這塊是AFNetworking中的安全框架财边,在iOS9之后網(wǎng)絡(luò)請(qǐng)求中加入SSL使用HTTPS幾乎已經(jīng)成為蘋果的強(qiáng)制要求了围苫。Security這部分主要功能就是用來(lái)驗(yàn)證HTTPS的證書是否有效俄精。這部分主要是通過AFSecurityPolicy這個(gè)類來(lái)實(shí)現(xiàn)的刁笙。
下面還是通過一個(gè)具體的調(diào)用來(lái)分析,就從AFNetworking的默認(rèn)調(diào)用開始滋尉,之前在分析NSURLSession部分時(shí)提到過玉控,在AFURLSessionManager的初始化方法中設(shè)置:
首先分析一下AFSecurityPolicy的這個(gè)初始化方法:
可看出在這一系列的初始化方法中主要設(shè)置了這兩個(gè)屬性,securityPolicy.SSLPinningMode = AFSSLPinningModeNone和self.validatesDomainName = YES狮惜。
表示是否驗(yàn)證域名高诺,默認(rèn)是YES碌识。
AFSSLPinningModeNone表示不使用固定證書(本地)驗(yàn)證服務(wù)器。直接從客戶端系統(tǒng)中的受信任頒發(fā)機(jī)構(gòu) CA 列表中去驗(yàn)證虱而。
AFSSLPinningModePublicKey代表會(huì)對(duì)服務(wù)器返回的證書中的PublicKey進(jìn)行驗(yàn)證筏餐,通過則通過,否則不通過牡拇。
AFSSLPinningModeCertificate代表會(huì)對(duì)服務(wù)器返回的證書同本地證書全部進(jìn)行校驗(yàn)魁瞪,通過則通過,否則不通過惠呼。
可看出AFNetworking默認(rèn)使用的是AFSSLPinningModeNone模式导俘。
繼續(xù)查看發(fā)現(xiàn)AFURLSessionManager會(huì)在這兩個(gè)地方使用這個(gè)屬性:
這兩個(gè)方法分別是實(shí)現(xiàn)了NSURLSessionDelegate和NSURLSessionTaskDelegate的協(xié)議方法。然后通過這方法里實(shí)現(xiàn)https的認(rèn)證剔蹋。服務(wù)端發(fā)起的一個(gè)驗(yàn)證挑戰(zhàn),客戶端需要根據(jù)挑戰(zhàn)的類型提供相應(yīng)的挑戰(zhàn)憑證旅薄。當(dāng)然,挑戰(zhàn)憑證不一定都是進(jìn)行HTTPS證書的信任,也可能是需要客戶端提供用戶密碼或者提供雙向驗(yàn)證時(shí)的客戶端證書。當(dāng)這個(gè)挑戰(zhàn)憑證被驗(yàn)證通過時(shí),請(qǐng)求便可以繼續(xù)順利進(jìn)行泣崩。下面具體分析認(rèn)證過程:
NSURLAuthenticationChallenge*類型的challenge 表示一個(gè)認(rèn)證的挑戰(zhàn)少梁,提供了關(guān)于這次認(rèn)證的全部信息。接著看:
challenge的protectionSpace屬性保存了需要認(rèn)證的保護(hù)空間矫付,NSURLProtectionSpace *類型的protectionSpace主機(jī)地址凯沪,端口和認(rèn)證方法等重要信息。由上邊代碼可知如果protectionSpace.authenticationMethod是NSURLAuthenticationMethodServerTrust技即,就對(duì)保護(hù)空間中的?serverTrust?以及域名host進(jìn)行認(rèn)證,并根據(jù)認(rèn)證的結(jié)果樟遣,會(huì)在?completionHandler?中傳入不同的disposition?和credential參數(shù)而叼。
繼續(xù)深入分析AFSecurityPolicy的認(rèn)證方法:
第一個(gè)條件分支
如果有服務(wù)器域名、設(shè)置了允許信任無(wú)效或者過期證書(自簽名證書)豹悬、需要驗(yàn)證域名葵陵、沒有提供證書或者不驗(yàn)證證書,返回NO瞻佛。
這一步為設(shè)置驗(yàn)證策略脱篙,如果要驗(yàn)證域名,就以域名為參數(shù)創(chuàng)建一個(gè)策略伤柄,否則創(chuàng)建默認(rèn)的basicX509策略绊困。
這一步是驗(yàn)證證書的有效性,如果是AFSSLPinningModeNone适刀,不做本地證書驗(yàn)證秤朗,從客戶端系統(tǒng)中的受信任頒發(fā)機(jī)構(gòu) CA 列表中去驗(yàn)證服務(wù)端返回的證書。但是如果不做本地證書驗(yàn)證笔喉,從客戶端系統(tǒng)中的受信任頒發(fā)機(jī)構(gòu) CA 列表中去驗(yàn)證服務(wù)端返回的證書通不過的話取视,而且allowInvalidCertificates不允許自簽硝皂,返回NO。
調(diào)用下面這個(gè)方法進(jìn)行驗(yàn)證有效性:
可看到這個(gè)方法里邊都是對(duì)系統(tǒng)庫(kù)<Security/Security.h>中方法的調(diào)用作谭。
接下來(lái)是通過不同的self.SSLPinningMode進(jìn)行對(duì)服務(wù)器信任的驗(yàn)證稽物。
如果是AFSSLPinningModeNone直接返回NO。
如果是AFSSLPinningModeCertificate:
首先把證書data用系統(tǒng)方法SecCertificateCreateWithData轉(zhuǎn)成 SecCertificateRef 類型的數(shù)據(jù)折欠,再調(diào)用系統(tǒng)方法SecTrustSetAnchorCertificates將pinnedCertificates設(shè)置成需要參與驗(yàn)證的Anchor Certificate(錨點(diǎn)證書)贝或。
參與校驗(yàn)錨點(diǎn)證書之后,假如驗(yàn)證的數(shù)字證書是這個(gè)錨點(diǎn)證書的子節(jié)點(diǎn)怨酝,即驗(yàn)證的數(shù)字證書是由錨點(diǎn)證書對(duì)應(yīng)CA或子CA簽發(fā)的傀缩,或是該證書本身,則信任該證書)农猬,具體就是調(diào)用SecTrustEvaluate來(lái)驗(yàn)證(如上)赡艰。
接下來(lái)這塊:
從我們需要被驗(yàn)證的服務(wù)端證書,去拿證書鏈斤葱,如果我們的證書中慷垮,有一個(gè)和它證書鏈中的證書匹配的,就返回YES揍堕。否則沒有匹配料身。(注意看:在匹配時(shí)調(diào)用了[serverCertificates reverseObjectEnumerator]這個(gè)方法得到一個(gè)前邊獲取的數(shù)組反轉(zhuǎn)后的數(shù)組,反轉(zhuǎn)前是從葉子節(jié)點(diǎn)到根節(jié)點(diǎn)衩茸,反轉(zhuǎn)后是從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)芹血。)
這個(gè)函數(shù)是通過調(diào)用系統(tǒng)的相關(guān)方法來(lái)獲取證書鏈。
如果是AFSSLPinningModePublicKey:
先調(diào)用AFPublicKeyTrustChainForServerTrust方法從serverTrust中取出服務(wù)器端傳過來(lái)的所有可用的證書楞慈,并依次得到相應(yīng)的公鑰幔烛。再通過雙重遍歷并調(diào)用方法AFSecKeyIsEqualToKey對(duì)比本地的證書公鑰和服務(wù)器傳過來(lái)的證書公鑰,如果相同的對(duì)數(shù)大于0囊蓝,則說明驗(yàn)證通過饿悬。
就此整個(gè)使用過程分析結(jié)束。和上篇的AFNetworkReachabilityManager類似聚霜,AFSecurityPolicy是對(duì)系統(tǒng)C語(yǔ)言安全庫(kù)<Security>的一個(gè)OC封裝狡恬,提供了簡(jiǎn)便易用的OC接口。