標籤:stop error serialize air 登陸 調用 原因 int false
每日更新關注:http://weibo.com/hanjunqiang 新浪微博!iOS開發人員交流QQ群: 446310206
一. HTTPS
其實HTTPS從最終的資料解析的角度,與HTTP沒有任何的區別,HTTPS就是將HTTP協議資料包放到SSL/TSL層加密後,在TCP/IP層組成IP資料報去傳輸,以此保證傳輸資料的安全;而對於接收端,在SSL/TSL將接收的資料包解密之後,將資料傳給HTTP協議層,就是普通的HTTP資料。HTTP和SSL/TSL都處於OSI模型的應用程式層。從HTTP切換到HTTPS是一個非常簡單的過程,在做具體的切換操作之前,我們需要瞭解幾個概念:
SSL/TLS
為了保證這些隱私資料能加密傳輸,於是網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的資料進行加密,從而就誕生了HTTPS。SSL目前的版本是3.0,被IETF(Internet Engineering Task Force)定義在RFC 6101中,之後IETF對SSL 3.0進行了升級,於是出現了TLS(Transport Layer Security) 1.0,定義在RFC 2246。實際上我們現在的HTTPS都是用的TLS協議,但是由於SSL出現的時間比較早,並且依舊被現在瀏覽器所支援,因此SSL依然是HTTPS的代名詞,但無論是TLS還是SSL都是上個世紀的事情,SSL最後一個版本是3.0,今後TLS將會繼承SSL優良血統繼續為我們進行Data Encryption Service。
SSL/TLS協議運行機制的概述
圖解SSL/TLS協議
簡單的來說,SSL/TSL通過四次握手。SSL協議的工作流程:
伺服器認證階段:
用戶端向伺服器發送一個開始資訊“Hello”以便開始一個新的會話串連;
伺服器根據客戶的資訊確定是否需要產生新的主要金鑰,如需要則伺服器在響應客戶的“Hello”資訊時將包含產生主要金鑰所需的資訊;
客戶根據收到的伺服器響應資訊,產生一個主要金鑰,並用伺服器的公開祕密金鑰加密後傳給伺服器;
伺服器恢複該主要金鑰,並返回給客戶一個用主要金鑰認證的資訊,以此讓客戶證明伺服器。
使用者認證階段:
在此之前,伺服器已經通過了客戶認證,這一階段主要完成對客戶的認證。
經認證的伺服器發送一個提問給客戶,客戶則返回(數字)簽名後的提問和其公開密鑰,從而向伺服器提供認證。
二. App Transport Security
iOS9中新增App Transport Security(簡稱ATS)特性, 主要使到原來請求的時候用到的HTTP,都轉向TLS1.2協議進行傳輸。這也意味著所有的HTTP協議都強制使用了HTTPS協議進行傳輸。在 iOS 9 和 OS X 10.11 中,預設情況下非 HTTPS 的網路訪問是被禁止的。當然,因為這樣的推進影響面非常廣,作為緩衝,我們可以在 Info.plist 中添加 NSAppTransportSecurity 字典並且將 NSAllowsArbitraryLoads 設定為 YES 來禁用 ATS。
不過,WWDC 16 中,Apple 表示將繼續在 iOS 10 和 macOS 10.12 裡收緊對普通 HTTP 的訪問限制。從 2017 年 1 月 1 日起,所有的新提交 app 預設是不允許使用 NSAllowsArbitraryLoads 來繞過 ATS 限制的,也就是說,我們最好保證 app 的所有網路請求都是 HTTPS 加密的,否則可能會在應用審核時遇到麻煩。
三. iOS10 NSAppTransportSecurity
通過在info.plist中配置這個鍵,開發人員可以自訂網路安全性原則。例如:
允許針對個別伺服器的不安全訪問。
允許不安全的 web 或媒體內容訪問,但不影響整個app的ATS策略。
啟用新的安全特性,例如Certificate Transparency。
對NSAppTransportSecurity的支援自 iOS9.0,OS X v10.11 開始,適用於 app 和 app extension。
自 iOS10.0,macOS 10.12 開始,增加了對下列子鍵的支援:
- NSAllowsArbitraryLoadsInMedia
- NSAllowsArbitraryLoadsInWebContent
- NSRequiresCertificateTransparency
- NSAllowsLocalNetworking
ATS Configuration Basics / ATS 配置基礎知識
對於使用 iOS9.0, OS X v10.11 SDK 及以上的 app 來說,ATS(App Transport Security)預設開啟,NSAllowsArbitraryLoads是字典NSAppTransportSecurity的根鍵,預設值NO。
在啟用 ATS 的情況下,所有的 HTTP 要求必須為 HTTPS(RFC 2818) 串連。任何不安全的 HTTP 要求都將失敗。ATS 使用 TLS(Transport Layer Security)v1.2(RFC 5246)。
下面是字典NSAppTransportSecurity的總體結構,所有鍵都是非必填項:
NSAppTransportSecurity : Dictionary { NSAllowsArbitraryLoads : Boolean NSAllowsArbitraryLoadsInMedia : Boolean NSAllowsArbitraryLoadsInWebContent : Boolean NSAllowsLocalNetworking : Boolean NSExceptionDomains : Dictionary { <domain-name-string> : Dictionary { NSIncludesSubdomains : Boolean NSExceptionAllowsInsecureHTTPLoads : Boolean NSExceptionMinimumTLSVersion : String NSExceptionRequiresForwardSecrecy : Boolean // Default value is YES NSRequiresCertificateTransparency : Boolean } }}
可以看出,所有鍵可以分為兩類:主鍵,這些鍵用來定義 app 的總體 ATS 策略;子鍵,即NSExceptionDomains下面的鍵,使用這些鍵針對某個網域名稱單獨配置。
主鍵包括:
NSAllowsArbitraryLoads
設定為 YES,解除整個 app 的 ATS 限制;但是,通過NSExceptionDomains進 行的配置依然有效。預設值為 NO。
注意:設定為 YES,會引發 App Stroe 的審查,開發人員必須說明原因。
NSAllowsArbitraryLoadsInMedia
設定為 YES,解除通過 AV Foundation 架構訪問媒體內容時的 ATS 限制;啟用這個 鍵,務必確保載入的媒體內容已經被加密,例如受FairPlay保護的檔案,或者是安全的 HLS流媒,其中不包含敏感的個人資訊。預設為 NO。
NSAllowsArbitraryLoadsInWebContent
設定為 YES,解除通過 web view 發出的網路請求的 ATS 限制。啟用這個鍵,可以使 app 訪問任意網頁內容,但不影響 app 的總體 ATS 策略。此索引值預設為 NO。
NSAllowsLocalNetworking
設定為 YES,使得 app 可以載入任意本地資源,但不影響 app 的總體 ATS 策略。默 認為 NO。
NSExceptionDomains
為一個或多個網域名稱單獨配置 ATS。
被單獨配置的網域名稱,預設受到完全的 ATS 限制,不管NSAllowsArbitraryLoads的值 如何;需要通過子鍵,進一步配置
所有的子鍵都屬於NSExceptionDomain。向Info.plist中添加這一主鍵:
- 建立字典,針對一個或多個網域名稱,以便進行 ATS 配置。
- 這意味著之前使用主鍵所做的設定,對於這個網域名稱來說,已經無效。
例如,及時之前設定NSAllowsArbitraryLoadsInMedia為 YES,然而NSExceptionDomain所代表的網域名稱依然不能訪問不安全的媒體內容。
基於這樣的設定,可以針對網域名稱進行 ATS 配置,增加或減少安全措施。例如:
- 將NSExceptionAllowsInsecureHTTPLoads設定為 YES,就 ;這樣做會引發 App Store 的審查,詳情見App Store Review for ATS。
- 通過配置NSExceptionRequiresForwardSecrecy為 NO,取消正向保密。
- 通過配置NSExceptionMinimumTLSVersion,更改 TLS 最低版本。
NSExceptionDomains字典構成:
Requirements for Connecting Using ATS / 使用 ATS 的前提條件
在 ATS 完全開啟的情況下,系統要求 app 的 HTTPS 串連必須滿足以下要求:
X.509 數位憑證必須滿足下列標準中的一項:
App Store Review for ATS / App Store 對於 ATS 相關項目的審核
某些對 ATS 的配置會引發 App Store 的審核,開發人員必須說明原因。這些鍵有:
- NSAllowsArbitraryLoads
- NSExceptionAllowsInsecureHTTPLoads
- NSExceptionMinimumTLSVersion
以下是一些原因說明例子,供參考:
- 必須串連由其他機構控制的伺服器,其還不支援安全連線。
- 必須支援那些還未升級至可使用安全連線,不得不通過公用網域名稱訪問網路的裝置。
- 必須通過 web 展示來源不一的各種網路內容,但又不能完全使用NSAllowsArbitraryLoadsInWebContent所管理的類。
向 App Store 提交審核時,開發人員應主動提供足夠的資訊,以便解釋 app 無法使用安全連線的原因。
四. 實現支援安全ATS策略
<font color=red size=5>ATS相關設定對iOS8及以下系統無效</font>
需要解決的問題(iOS 9、iOS10及以上)1、app內伺服器網路請求訪問支援https(即一般的請求)2、webview內支援任意http訪問3、第三方sdk接入與支援http訪問主要是圍繞info.pilst設定檔作相關的安全ATS策略
Info.plist檔案是向作業系統描述應用程式的XML屬性列表,是iPhone應用程式檔案夾包含所有重要的Info.plist檔案
你可能注意到一些關鍵字像是使用了一些其他關鍵字中的詞但是在前面加上了"ThirdParty"字樣,在功能上,這些關鍵字與不含有"ThirdParty"的關鍵字有同樣的效果。而且實際運行中所調用的代碼將會完全忽略是否使用"ThirdParty"關鍵字。
簡單粗暴的方案:
--------------------------------------------
NSExceptionDomains 的設定方法如下, 比如我們要將 weibo.com 這個網域名稱排除在 ATS 驗證之外,就可以這樣:
key>NSAppTransportSecurity</key><dict> <key>NSExceptionDomains</key> <dict> <key>weibo.com</key> <dict> <key> NSIncludesSubdomains </key> <true/> <key> NSExceptionRequiresForwardSecrecy </key> <false/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> <key>NSAllowsArbitraryLoads</key> <true/></dict>
注意:每個需添加的域都需要設定此三個屬性。如果請求的網狀圖片是HTTP,也是需要設定的圖片的域。
注意??這個方案風險較大,有可能被拒絕。“需要訪問的網域名稱是第三方伺服器,他們沒有進行 HTTPS 對應”會是審核時的一個可選理由,但是這應該只需要針對特定網域名稱,而非全面開放。如果訪問的是自己的伺服器的話,可能這個理由會無法通過。
------------------------------------------------
實現方案1、app內伺服器網路請求訪問支援https
解決方案:
搭建https伺服器
搭建https伺服器需要ssl認證
- ssl自製認證:稱自簽名ssl認證,容易被假冒偽造,瀏覽器不信任。(審核不通過)
- 免費CA認證:部分CA機構提供免費的SSL認證,如wosign,starts等(App Store pass掉不通過)
- 付費CA認證:多指企業級及以上的數位憑證。
HTTPS伺服器滿足ATS預設的條件,而且SSL認證是通過權威的CA機構認證過的,那麼我們在使用Xcode開發的時候,對網路的適配什麼都不用做,我們也能正常與伺服器通訊。但是,當我們對安全性有更高的要求時或者我們自建認證時,我們需要本地匯入認證來進行驗證。
使用AFNetworking來支援https
AFNetworking是iOS/OSX開發最流行的第三方開源庫之一,現在iOS oc 代碼90%以上都是用這個架構網路請求。AFNetworking已經將上面的邏輯代碼封裝好,甚至更完善,在AFSecurityPolicy檔案中,有興趣可以閱讀這個模組的代碼;以下就是在AFNetworking 2.6.0以前版本和3.0.0版本基於支援https的驗證方式
步驟:
- 建立一個manager
- 在mainBundle中尋找我們剛才拖進項目中的https.cer, 並且將相關的資料讀取出來
- 建立一個AFSecurityPolicy,並進行相應的配置
- 將這個AFSecurityPolicy 執行個體賦值給manager
代碼實現:
NSURL * url = [NSURL URLWithString:@"https://www.google.com"];AFHTTPRequestOperationManager * requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name("kRequestCompletionQueue");requestOperationManager.completionQueue = requestQueue;AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];//allowInvalidCertificates 是否允許無效認證(也就是自建的認證),預設為NO//如果是需要驗證自建認證,需要設定為YESsecurityPolicy.allowInvalidCertificates = YES;//validatesDomainName 是否需要驗證網域名稱,預設為YES;//假如認證的網域名稱與你請求的網域名稱不一致,需把該項設定為NO;如設成NO的話,即伺服器使用其他可信任機構頒發的認證,也可以建立串連,這個非常危險,建議開啟。//置為NO,主要用於這種情況:用戶端請求的是子網域名稱,而認證上的是另外一個網域名稱。因為SSL認證上的網域名稱是獨立的,假如認證上註冊的網域名稱是www.google.com,那麼mail.google.com是無法驗證通過的;當然,有錢可以註冊萬用字元的網域名稱*.google.com,但這個還是比較貴的。//如置為NO,建議自己添加對應網域名稱的校正邏輯。securityPolicy.validatesDomainName = YES;//validatesCertificateChain 是否驗證整個憑證鏈結,預設為YES//設定為YES,會將伺服器返回的Trust Object上的憑證鏈結與本地匯入的認證進行對比,這就意味著,假如你的憑證鏈結是這樣的://GeoTrust Global CA // Google Internet Authority G2// *.google.com//那麼,除了匯入*.google.com之外,還需要匯入憑證鏈結上所有的CA認證(GeoTrust Global CA, Google Internet Authority G2);//如是自建認證的時候,可以設定為YES,增強安全性;假如是信任的CA所簽發的認證,則建議關閉該驗證,因為整個憑證鏈結一一比對是完全沒有必要(請查看原始碼);securityPolicy.validatesCertificateChain = NO;requestOperationManager.securityPolicy = securityPolicy;另afnetworking 3.0.0以上版本用的是AFHTTPSessionManager AFHTTPSessionManager * manager = [AFHTTPSessionManager manager]; NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"]; NSData * cerData = [NSData dataWithContentsOfFile:cerPath]; NSLog(@"%@", cerData); manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSArray alloc] initWithObjects:cerData, nil]]; manager.securityPolicy.allowInvalidCertificates = YES; [manager.securityPolicy setValidatesDomainName:NO]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFJSONResponseSerializer serializer]; NSDictionary * parameter = @{@"username":self.username, @"password":self.password}; [manager POST:@"https://192.168.1.4:9777" parameters:parameter success:^(NSURLSessionDataTask * task, id responseObject) { NSLog(@"success %@", responseObject); } failure:^(NSURLSessionDataTask * task, NSError * error) { NSLog(@"failure %@", error); }] <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> //設定為 YES,解除整個app的ATS限制;但是通過NSExceptionDomains進行的配置依然有效 <false/> <key>NSAllowsArbitraryLoadsInMedia</key> //設定為 YES,解除通過AVFoundation架構訪問媒體內容時的 ATS 限制 <true/> <key>NSAllowsArbitraryLoadsInWebContent</key> //設定為 YES,解除通過webview發出的網路請求的ATS限制 <true/> <key>NSAllowsLocalNetworking</key> //設定為 YES,使得app可以載入任意本地資源,但不影響app的總體 ATS 策略 <true/>
2、webview內支援任意http訪問
對於網頁瀏覽和視頻播放的行為,iOS 10 中新加入了 NSAllowsArbitraryLoadsInWebContent 鍵。通過將它設定為 YES,可以讓 app 中的 WKWebView 和使用 AVFoundation 播放的線上視頻不受 ATS 的限制。這也應該是絕大多數使用了相關特性的 app 的選擇。但是壞訊息是這個鍵在 iOS 9 中並不會起作用。
如果app只支援 iOS 10,並且有使用者可以自由輸入網址進行瀏覽的功能,或者是線上視頻音頻播放功能的話,簡單地加入 NSAllowsArbitraryLoadsInWebContent,並且將組件換成 WKWebKit 或者 AVFoundation 就可以了。如果你還需要支援 iOS 9,並且需要訪問網頁和視頻的話,可能只能去開啟 NSAllowsArbitraryLoads 然後提交時進行說明,並且看 Apple 審核員決定讓不讓通過了。
另外,當 NSAllowsArbitraryLoads 和 NSAllowsArbitraryLoadsInWebContent 同時存在時,根據系統不同,表現的行為也會不一樣。簡單說,iOS 9 只看 NSAllowsArbitraryLoads,而 iOS 10 會先看 NSAllowsArbitraryLoadsInWebContent。在 iOS 10 中,要是 NSAllowsArbitraryLoadsInWebContent 存在的話,就忽略掉 NSAllowsArbitraryLoads,如果它不存在,則遵循 NSAllowsArbitraryLoads 的設定
UIWebView 在 NSAllowsArbitraryLoadsInWebContent 為 YES 時訪問 HTTP,無效。WKWebView 在 NSAllowsArbitraryLoadsInWebContent 為 YES 時在iOS 10 中訪問 HTTP,有效,iOS 9無效。如果用WkWebView替換UIWebView,iOS 7 將無法使用WkWebView,可做適配載入,沒有特殊的什麼需求的話,儘早將 UIWebView 全部換為 WkWebView 會比較好。所以為了能讓WebView在所有版本都能訪問非https內容,只能把NSAllowsArbitraryLoads設定為YES。
解決方案一:
開啟 NSAllowsArbitraryLoads 為 YES,然後提交時進行說明
解決方案二:
設定 NSExceptionDomains 屬性來訪問指定網域名稱,然後提交時進行說明
3、第三方sdk接入與支援http訪問
但是按照國內的現狀,關閉這個限制也許是更實際的做法。至於原因就太多了,第三方SDK(幾乎都是訪問http),夥伴接入(不能要求它們一定要支援https)
第三方sdk,同樣需要遵守ATS規則,即第三方sdk也有被ATS過濾的風險,,qq,分享,登陸功能都能正常,微博登陸不能正常通過。另在網上找到了一些可能存在有問題的sdk,目前已知的有:
- 友盟 (已經有最新的v1.4.0版本sdk,支援https,待驗證)
- 百度地圖
解決方案一:
更新最新sdk,接入並測試
解決方案二:
可以設定 NSExceptionDomains屬性來將需要排除強制驗證的網域名稱寫進來:
五. 總結
開啟 NSAllowsArbitraryLoads 為 YES
對第三方訪問的伺服器設定NSExceptionDomains方式添加白名單
提交審核說明:
每日更新關注:http://weibo.com/hanjunqiang 新浪微博!
iOS開發人員交流QQ群: 446310206
iOS10 適配 ATS(app支援https通過App Store審核) 韓俊強的部落格