<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS 簡單模擬 https 證書信任邏輯

          共 5831字,需瀏覽 12分鐘

           ·

          2021-11-23 15:44

          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????


          作者:頭疼腦脹的代碼搬運工

          來源:稀土掘金

          鏈接:

          https://juejin.cn/post/7030345610704191501


          開篇:https 證書是什么?如何進(jìn)行認(rèn)證呢?帶著這些疑問來簡單的實現(xiàn)一下驗證過程

          簡單的了解一下 https 在數(shù)據(jù)傳輸前的一些操作,如圖:

          這里總結(jié)一下上面的流程圖關(guān)鍵的步驟:

          1、認(rèn)證網(wǎng)絡(luò)請求的安全性

          服務(wù)器會在建立真正的數(shù)據(jù)傳輸之前返回一個公鑰數(shù)字證書。這里客戶端需要在 URLSession 進(jìn)行認(rèn)證挑戰(zhàn)方法回調(diào)里進(jìn)行判斷然后確定是否要繼續(xù)進(jìn)行請求。代理方法如下:

          - (void)URLSession:(NSURLSession *)session

          task:(NSURLSessionTask *)task

          didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

          completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler

          可以這樣理解,URLSessionhttps 網(wǎng)絡(luò)請求的時候其實會把請求鑒權(quán)的權(quán)限通過代理的方法給暴露出來,是否信任并繼續(xù)建立連接可以按照特定規(guī)則去執(zhí)行(如自簽證書),只有 https 請求會走代理方法,http 則不進(jìn)行回調(diào),這也是為什么 iOS系統(tǒng) 為什么提倡使用 https 的原因。

          2、認(rèn)證通過,通過公私鑰非對稱加密方式對最后的對稱加密密鑰進(jìn)行加、解密:

          這話聽起來有點繞,基于第一步的公鑰數(shù)字證書信任,那么,生成一個用于請求數(shù)據(jù)對稱加密的密鑰(對稱加密更快),用這個公鑰進(jìn)行非對稱加密,在由服務(wù)器的私鑰進(jìn)行解密,得到這個密鑰,那么,真正建立的數(shù)據(jù)傳輸就以此密鑰進(jìn)行加、解密。

          下面,模擬一下如何進(jìn)行的公鑰證書受信

          創(chuàng)建 公鑰.der 及 證書.cer 文件

          在終端依次輸入如下命令:

          //生成私鑰
          openssl genrsa -out private_key.pem 1024

          //獲取 證書.cer
          openssl req -new -key private_key.pem -out rsaCertReq.csr

          openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt

          //將 .crt 格式證書轉(zhuǎn)換為 .cer 格式證書,后面iOS程序里需要 .cer格式證書
          openssl x509 -in rsaCert.crt -out rsaCert.cer -outform der

          //獲得 公鑰.der
          openssl x509 -outform der -in rsaCert.crt -out public_key.der


          過程中會有一些簡單信息輸入,這里沒有特別的要求,文件創(chuàng)建后目錄如圖:

          .cer 格式證書公鑰.der 格式證書 全部拖到工程里:

          下面輸出一段代碼,用 .cer 證書去驗證 公鑰.der 是否可信。

          - (void)trustIsVaild

          {
          //獲取工程下所有cer證書(https 網(wǎng)絡(luò)請求鑒權(quán)必需證書)
          NSArray *paths = [[NSBundle mainBundle] pathsForResourcesOfType:@"cer" inDirectory:@"."];

          //保存工程內(nèi)的所有 cer 證書(并在后面設(shè)置為鑒權(quán)錨點)
          NSMutableArray *pinnedCertificates = [NSMutableArray array];

          for (NSString *path in paths) {

          NSData *certificateData = [NSData dataWithContentsOfFile:path];

          [pinnedCertificates addObject:( __bridge_transfer id)SecCertificateCreateWithData(NULL, ( __bridge CFDataRef)certificateData)];

          }

          //獲取工程下的公鑰數(shù)字證書(在https網(wǎng)絡(luò)請求認(rèn)證挑戰(zhàn)中由服務(wù)器返回)
          NSString * publicKeyPath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];

          NSData *derData = [[NSData alloc] initWithContentsOfFile:publicKeyPath];

          //證書資源
          SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef)derData);

          //驗證政策設(shè)置
          SecPolicyRef myPolicy = SecPolicyCreateBasicX509();

          SecTrustRef myTrust;

          //SecTrust 賦值
          OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);

          if (status == noErr) {
          //設(shè)置證書錨點(這里的意思就是如果鑒權(quán)到指定的證書是有效的,那么,就信任此公鑰數(shù)字簽名,這里如果不設(shè)置,那么就會一直找向根證書,由于工程里的公鑰數(shù)字證書是自簽的,所以,一定不會受信)
          SecTrustSetAnchorCertificates(myTrust, ( __bridge CFArrayRef)pinnedCertificates);

          SecTrustResultType result;

          if (SecTrustEvaluate(myTrust, &result) == 0) {

          //kSecTrustResultUnspecified 隱式信任
          //kSecTrustResultProceed 可繼續(xù)進(jìn)行
          if ((result == kSecTrustResultUnspecified || result == kSecTrustResultProceed)) {

          NSLog(@"受信任的證書");

          } else {

          NSLog(@"未受信任的證書");

          }

          } else {

          NSLog(@"未受信任的證書初始化操作失敗");

          }

          }

          }

          運行如下:

          順便輸出一下不設(shè)置 證書錨點 控制臺內(nèi)容:

          if (status == noErr) {
          //不設(shè)置錨點
          //SecTrustSetAnchorCertificates(myTrust, (__bridge CFArrayRef)pinnedCertificates);

          SecTrustResultType result;

          if (SecTrustEvaluate(myTrust, &result) == 0) {

          if ((result == kSecTrustResultUnspecified || result == kSecTrustResultProceed)) {

          NSLog(@"受信任的證書");

          } else {

          NSLog(@"未受信任的證書");
          }
          } else {

          NSLog(@"未受信任的證書初始化操作失敗");
          }
          }

          到這里,公鑰證書如果受信,那么,下一步就規(guī)定一個 對稱加密 session key 用這個公鑰加密,發(fā)送到服務(wù)器,然后用對應(yīng)的私鑰解密,供以后的數(shù)據(jù)傳輸進(jìn)行 對稱加密 操作。

          所以,移動端在做自定義證書鑒權(quán)的時候就需要存儲服務(wù)器生成的 .cer 證書文件!

          AFNetworking 下的鑒權(quán)方式處理相對復(fù)雜,因為 URLSession 的認(rèn)證挑戰(zhàn)回調(diào)是允許程序員全部無條件開啟的,所以,AFNetworking 在默認(rèn)鑒權(quán)行為的基礎(chǔ)上添加了幾種自定義鑒權(quán)方式:

          typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {

          AFSSLPinningModeNone,//無條件開啟

          AFSSLPinningModePublicKey,//認(rèn)證公鑰內(nèi)容

          AFSSLPinningModeCertificate,//認(rèn)證證書

          };

          而且,在此之前 AFNetworking 通過

          @property (readwrite, nonatomic, copy) AFURLSessionTaskAuthenticationChallengeBlock authenticationChallengeHandler;

          暴露給外界閉包進(jìn)行自定義鑒權(quán)邏輯及處理結(jié)果。

          - (void)URLSession:(NSURLSession *)session

          task:(NSURLSessionTask *)task

          didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
          completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
          {
          BOOL evaluateServerTrust = NO;
          NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
          NSURLCredential *credential = nil;

          //AFNetworking 暴露給程序員自定義處理入口
          if (self.authenticationChallengeHandler) {
          id result = self.authenticationChallengeHandler(....);
          ... (解析處理結(jié)果)
          }
          ...(證書認(rèn)證處理代碼)

          //最后調(diào)用 completionHandler 繼續(xù)執(zhí)行操作
          if (completionHandler) {

          completionHandler(disposition, credential);

          }
          }

          disposition: 可以設(shè)置繼續(xù)鑒權(quán)挑戰(zhàn)(NSURLSessionAuthChallengeUseCredential) 或者中斷鑒權(quán)挑戰(zhàn)(NSURLSessionAuthChallengeCancelAuthenticationChallenge

          credential: 如果證書認(rèn)證通過則直接進(jìn)行賦值,

          credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

          否則為 nil

          這里只是簡單的梳理一下證書信任邏輯,就不再贅述 AFNetworking 源碼部分。


          作者:頭疼腦脹的代碼搬運工

          來源:稀土掘金

          鏈接:

          https://juejin.cn/post/7030345610704191501

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點這里好文分享給更多人↓↓

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品大奶自慰 | 一本道亚洲 | 操美女国产 | 天天爽日日爽夜夜爽 | 亚洲激情片 |