因爲蘋果規定2017年1月1日之後,全部APP都要使用HTTPS進行網絡請求,不然沒法上架,所以研究了一下在iOS中使用HTTPS請求的實現。網上搜索了一些比較有用資料,你們能夠參考下 算法
蘋果強制升級的HTTPS不單單是在接口HTTP上加個S那麼簡單: json
它全部知足的是iOS9中新增App Transport Security(簡稱ATS)特性: vim
那知足ATS咱們須要作什麼呢 瀏覽器
1.必須是蘋果信任的CA證書機構頒發的證書 安全
2.後臺傳輸協議必須知足: TLS1.2 (這很重要, 後面的自制證書知足這個條件是前提) 服務器
3.簽字算法只能是下面的一種: 網絡
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384session
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256app
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384框架
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
4.證書必須使用SHA256或者更好的哈希算法進行簽名,要麼是2048位或者更長的RSA密鑰,要麼就是256位或更長的ECC密鑰。
目前有兩種升級到HTTPS得方法:
1.第三方認證的頒發CA證書(推薦)
2.本身製做證書(這種不知道能不能知足蘋果的審覈)
一: 第三方認證的頒發CA證書
證書到底長什麼樣子呢? 取個栗子:
而後看到
百度的證書分析
哪些證書機構頒發的證書能用:蘋果官方信任證書
收費SSL證書: 網上百度一大把, 收費還挺貴的,本身能夠多找幾個對比一下
免費SSL證書: 除了收費的CA證書機構, 你還能夠去騰訊雲申請免費的SSL證書, 教程免費在騰訊雲申請SSL證書的方法
沃通(WoSign)免費的SSL證書最近被蘋果封殺了, 能不能用你們能夠看一下蘋果的公告: 您的蘋果手機輕點「設置」>「通用」>「關於本機」>"證書信任設置">"進一步瞭解被信任的證書"去了解
檢測你的接口是否知足蘋果的ATS要求, 有如下兩種方法:
1. 騰訊雲提供的檢測頁面檢測
2 終端輸入 nsurl --ats-diagnostics --verbose 你的接口地址
你們能夠參考這篇文章,裏面的說的很明白:
關於iOS9中的App Transport Security相關說明及適配(更新於2016.7.1)
裏面會詳細說明你的證書哪點不符合ATS要求
固然下面本身製做證書去實現HTTPS的,檢測不經過的,因此我以爲審覈會被拒
這種方法配置好了, 在手機端就什麼都不用配置就能夠請求了
二: 本身製做證書
蘋果官方信任證書裏說到有三種證書:
1 可信的根證書用於創建信任鏈,以驗證由可信的根簽署的其餘證書,例如,與 Web 服務器創建安全鏈接。當 IT 管理員建立 iPhone、iPad 或 iPod touch 的配置描述文件時,無需提供這些可信的根證書。
2 始終詢問的證書不受信任,但不受阻止。使用其中一個證書時,系統將提示您選擇是否信任該證書。
3 已阻止的證書視爲被盜用,將再也不受信任。
自制證書我以爲應該就是屬於第二種狀況, 因此這種方法我也不知道能不能經過蘋果的審覈, 只是提供一個方法給你們參考, 看到網上有人說能夠,有人說不能夠, 不到1月1號,本身沒試過都不敢說大話
這種方式拿到後臺的接口用谷歌瀏覽器打開跟百度的證書是有區別的
本身製做證書
很明顯沒有綠鎖, 當打開的時候會詢問是否鏈接這個不受信任的鏈接纔會進一步打開, 下面就來一步步的實現(包括怎麼製做證書)
iOS Https協議 自簽證書訪問數據參考這個例子的時候,博主自帶的Demo AFN框架請求不了數據, 我用了最新AFN版本的成功返回數據
還能夠參考一下
iOS 10 適配 ATS app支持https經過App Store審覈
我在利用原生的代碼測試時遇到的問題
@implementation ViewController - (void)viewDidLoad { } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }]; [task resume]; } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { NSLog(@"接收到服務器響應"); //注意:這裏須要使用completionHandler回調告訴系統應該如何處理服務器返回的數據 //默認是取消 /** NSURLSessionResponseCancel = 0, 默認的處理方式,取消 NSURLSessionResponseAllow = 1, 接收服務器返回的數據 NSURLSessionResponseBecomeDownload = 2, 變成一個下載請求 NSURLSessionResponseBecomeStream 變成一個流 */ completionHandler(NSURLSessionResponseAllow); } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSLog(@"獲取到服務段數據"); NSLog(@"%@",[self jsonToDictionary:data]); } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error { NSLog(@"請求完成%@", error); } - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { NSLog(@"證書認證"); if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) { do { SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; NSCAssert(serverTrust != nil, @"serverTrust is nil"); if(nil == serverTrust) break; /* failed */ /** * 導入多張CA證書(Certification Authority,支持SSL證書以及自簽名的CA),請替換掉你的證書名稱 */ NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];//自簽名證書 NSData* caCert = [NSData dataWithContentsOfFile:cerPath]; NSCAssert(caCert != nil, @"caCert is nil"); if(nil == caCert) break; /* failed */ SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert); NSCAssert(caRef != nil, @"caRef is nil"); if(nil == caRef) break; /* failed */ //能夠添加多張證書 NSArray *caArray = @[(__bridge id)(caRef)]; NSCAssert(caArray != nil, @"caArray is nil"); if(nil == caArray) break; /* failed */ //將讀取的證書設置爲服務端幀數的根證書 OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray); NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed"); if(!(errSecSuccess == status)) break; /* failed */ SecTrustResultType result = -1; //經過本地導入的證書來驗證服務器的證書是否可信 status = SecTrustEvaluate(serverTrust, &result); if(!(errSecSuccess == status)) break; /* failed */ NSLog(@"stutas:%d",(int)status); NSLog(@"Result: %d", result); BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed); if (allowConnect) { NSLog(@"success"); }else { NSLog(@"error"); } /* kSecTrustResultUnspecified and kSecTrustResultProceed are success */ if(! allowConnect) { break; /* failed */ } #if 0 /* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success */ /* since the user will likely tap-through to see the dancing bunnies */ if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError) break; /* failed to trust cert (good in this case) */ #endif // The only good exit point NSLog(@"信任該證書"); NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential,credential); return [[challenge sender] useCredential: credential forAuthenticationChallenge: challenge]; } while(0); } // Bad dog NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,credential); return [[challenge sender] cancelAuthenticationChallenge: challenge]; } - (NSDictionary *)jsonToDictionary:(NSData *)jsonData { NSError *jsonError; NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&jsonError]; return resultDic; } @end 下面說說我在配置本身製做證書過程當中遇到的問題: 1.轉換證書: 把後臺給你的.crt證書轉化爲.cer後綴 終端命令行openssl x509 -in 你的證書.crt -out 你的證書.cer -outform der 2.利用系統的方法來不到 1 2 3 4 - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler { NSLog(@"證書認證"); }
這個方法的時候, 是由於後臺的傳輸協議還沒升級到TLS1.2, 叫後臺升級後就能夠來到驗證證書的這個方法了.
3.拖入證書讀取不出證書數據
參考: https的證書錯誤,錯誤碼-1012問題及解決方案
SDWebImage: 項目中你們用到AFN請求網絡數據, 升級驗證SSL證書的方案相信你看完上面的參考文章已經沒問題了, 我給出的代碼, 自定義網絡請求也沒問題了, 還有就是SDWebImage框架的請求HTTPS的圖片時,你們能夠繞過證書驗證去加載圖片
1
[imageView sd_setImageWithURL:[NSURL URLWithString:urlString] placeholderImage:self.placeholder options:SDWebImageAllowInvalidSSLCertificates];
但願幫到你。