iOS 10 適配 ATS(app支持https經過App Store審覈)

iOS 10 適配 ATS

一. HTTPS

其實HTTPS從最終的數據解析的角度,與HTTP沒有任何的區別,HTTPS就是將HTTP協議數據包放到SSL/TSL層加密後,在TCP/IP層組成IP數據報去傳輸,以此保證傳輸數據的安全;而對於接收端,在SSL/TSL將接收的數據包解密以後,將數據傳給HTTP協議層,就是普通的HTTP數據。HTTP和SSL/TSL都處於OSI模型的應用層。從HTTP切換到HTTPS是一個很是簡單的過程,在作具體的切換操做以前,咱們須要瞭解幾個概念:html

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優良血統繼續爲咱們進行加密服務。web

簡單的來講,SSL/TSL經過四次握手。SSL協議的工做流程:安全

服務器認證階段:服務器

客戶端向服務器發送一個開始信息「Hello」以便開始一個新的會話鏈接;
服務器根據客戶的信息肯定是否須要生成新的主密鑰,如須要則服務器在響應客戶的「Hello」信息時將包含生成主密鑰所需的信息;
客戶根據收到的服務器響應信息,產生一個主密鑰,並用服務器的公開密鑰加密後傳給服務器;
服務器恢復該主密鑰,並返回給客戶一個用主密鑰認證的信息,以此讓客戶認證服務器。微信

用戶認證階段:網絡

在此以前,服務器已經經過了客戶認證,這一階段主要完成對客戶的認證。
經認證的服務器發送一個提問給客戶,客戶則返回(數字)簽名後的提問和其公開密鑰,從而向服務器提供認證。app

二. 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字典構成:

  • <域名字符串>
    表明想要配置的特定域名。能夠添加多個域名(即添加多個這樣的鍵),爲它們統一配置 ATS 策略。這個鍵對應一個字典,包含如下子鍵:

    • NSIncludesSubdomains
      * 設置爲 YES,當前域名的 ATS 策略適用於其全部子域名。默認爲 NO。
    • NSExceptionAllowsInsecureHTTPLoads
      * 設置爲 YES,能夠同時經過 HTTP 和 HTTPS 訪問當前域名。默認爲 NO。 注意,配置這個鍵值,將引起 App Store 的審查,開發者必須說明緣由。
    • NSExceptionMinimumTLSVersion
      * 指定 TLS 的最低版本,所以可使用版本較低,有安全漏洞的 TLS 協議。 注意,配置這個鍵值,將引起 App Store 的審查,開發者必須說明緣由。
    • NSExceptionRequiresForwardSecrecy
      * 設置爲 NO,容許針對當前域名使用不支持正向保密的 TLS 加密算法。默認爲 YES。
    • NSRequiresCertificateTransparency
      * 設置爲 YES,將驗證域名服務器證書的Certificate Transparency時間戳 。默認爲 NO。

Requirements for Connecting Using ATS / 使用 ATS 的前提條件

在 ATS 徹底開啓的狀況下,系統要求 app 的 HTTPS 鏈接必須知足如下要求:

X.509 數字證書必須知足下列標準中的一項:

  • 由操做系統內嵌的根證書頒發機構簽發

    • 由經過操做系統管理員或用戶主動安裝的根證書頒發機構簽發
      • TLS 版本必須爲1.2,任何不使用或使用較低版本 TLS / SSL 的鏈接,都將失敗。
  • 鏈接必須使用 AES-128 或 AES-256 對稱加密算法。 TLS 算法套裝必須以 ECDSA 密鑰交換的形式支持正向保密,加密算法必須爲下面之一:

    • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    • 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
  • 服務端的葉證書籤名密鑰必須爲下面之一:

    • 至少2048位的 RSA 密鑰
    • 至少256位的 ECC 密鑰
    • 此外,服務器證書的哈希算法必須爲 SHA-2,其摘要長度至少位256位(即 SHA-256 及以上)。
      上面的標準,將來可能會發生變化。但不會影響到 app 二進制包的兼容性。

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 九、iOS10及以上)

一、app內服務器網絡請求訪問支持https(即通常的請求)

二、webview內支持任意http訪問

三、第三方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 對應」會是審覈時的一個可選理由,可是這應該只須要針對特定域名,而非全面開放。若是訪問的是本身的服務器的話,可能這個理由會沒法經過。

------------------------------------------------

實現方案

一、app內服務器網絡請求訪問支持https

解決方案:

搭建https服務器

搭建https服務器須要ssl證書

  1. ssl自制證書:稱自簽名ssl證書,容易被假冒僞造,瀏覽器不信任。(審覈不經過)
  2. 免費CA證書:部分CA機構提供免費的SSL證書,如wosign,starts等(App Store pass掉不經過)
  3. 付費CA證書:多指企業級及以上的數字證書。

HTTPS服務器知足ATS默認的條件,並且SSL證書是經過權威的CA機構認證過的,那麼咱們在使用Xcode開發的時候,對網絡的適配什麼都不用作,咱們也能正常與服務器通訊。可是,當咱們對安全性有更高的要求時或者咱們自建證書時,咱們須要本地導入證書來進行驗證。

使用AFNetworking來支持https

AFNetworking是iOS/OSX開發最流行的第三方開源庫之一,如今iOS oc 代碼90%以上都是用這個框架網絡請求。AFNetworking已經將上面的邏輯代碼封裝好,甚至更完善,在AFSecurityPolicy文件中,有興趣能夠閱讀這個模塊的代碼;如下就是在AFNetworking 2.6.0之前版本和3.0.0版本基於支持https的驗證方式

步驟:

  1. 新建一個manager
  2. 在mainBundle中尋找咱們剛纔拖進項目中的https.cer, 而且將相關的數據讀取出來
  3. 新建一個AFSecurityPolicy,並進行相應的配置
  4. 將這個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 //若是是須要驗證自建證書,須要設置爲YES securityPolicy.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/>

二、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 屬性來訪問指定域名,而後提交時進行說明

三、第三方sdk接入與支持http訪問

可是按照國內的現狀,關閉這個限制也許是更實際的作法。至於緣由就太多了,第三方SDK(幾乎都是訪問http),合做夥伴接入(不能要求它們必定要支持https)

第三方sdk,一樣須要遵照ATS規則,即第三方sdk也有被ATS過濾的風險,微信,qq,分享,登錄功能都能正常,微博登錄不能正常經過。另在網上找到了一些可能存在有問題的sdk,目前已知的有:

  • 友盟 (已經有最新的v1.4.0版本sdk,支持https,待驗證)
  • 百度地圖

解決方案一:

更新最新sdk,接入並測試

解決方案二:

能夠設置 NSExceptionDomains屬性來將須要排除強制驗證的域名寫進來:

五. 總結

開啓 NSAllowsArbitraryLoads 爲 YES

對第三方訪問的服務器設置NSExceptionDomains方式添加白名單

提交審覈說明:

  • 必須鏈接由其餘機構控制的服務器,其還不支持安全鏈接。

  • 必須經過 web 展現來源不一的各類網絡內容,但又不能徹底使用NSAllowsArbitraryLoadsInWebContent所管理的類。

相關文章
相關標籤/搜索