1. 程式人生 > >關於 iOS 10 中 ATS 的問題

關於 iOS 10 中 ATS 的問題

完全 app 系統 發現 base afa efault 就會 安全性

WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推進網絡通訊安全的一個重要方式。在 iOS 9 和 OS X 10.11 中,默認情況下非 HTTPS 的網絡訪問是被禁止的。當然,因為這樣的推進影響面非常廣,作為緩沖,我們可以在 Info.plist 中添加 NSAppTransportSecurity 字典並且將 NSAllowsArbitraryLoads 設置為 YES 來禁用 ATS。相信大家都已經對這個非常熟悉了,因為我自己也維護了一些網絡相關的框架,所以我還自己準備了一個小腳本來快速關閉 ATS。

不過,WWDC 16 中,Apple 表示將繼續在 iOS 10 和 macOS 10.12 裏收緊對普通 HTTP 的訪問限制。從 2017 年 1 月 1 日起,所有的新提交 app 默認是不允許使用 NSAllowsArbitraryLoads

來繞過 ATS 限制的,也就是說,我們最好保證 app 的所有網絡請求都是 HTTPS 加密的,否則可能會在應用審核時遇到麻煩。

現在 (2016-11-28),這方面的相關規定和幾個事實如下:

  1. 默認情況下你的 app 可以訪問加密足夠強 (TLS v1.2 以上,AES-128 和 SHA-2 以及 ECDHC 等) 的 HTTPS 內容。這對所有的網絡請求都有效,包括 NSURLSession,通過 AVFoundation 訪問的流媒體,UIWebView 以及 WKWebView 等。
  2. 你依然可以添加 NSAllowsArbitraryLoadsYES 來全面禁用 ATS,不過如果你這麽做的話,需要在提交 app 時進行說明,為什麽需要訪問非 HTTPS 內容。一般來說,可能簡單粗暴地開啟這個選項,而又無法找到正當理由的 app 會難以通過審核。
  3. 相比於使用 NSAllowsArbitraryLoads 將全部 HTTP 內容開放,選擇使用 NSExceptionDomains 來針對特定的域名,通過設定該域名下的 NSExceptionAllowsInsecureHTTPLoads 來開放 HTTP 應該要相對容易過審核。“需要訪問的域名是第三方服務器,他們沒有進行 HTTPS 對應”會是審核時的一個可選理由,但是這應該只需要針對特定域名,而非全面開放。如果訪問的是自己的服務器的話,可能這個理由會無法通過。
  4. 對於網頁瀏覽和視頻播放的行為,iOS 10 中新加入了 NSAllowsArbitraryLoadsInWebContent
    NSAllowsArbitraryLoadsForMedia 鍵。通過將它們設置為 YES,可以讓你的 app 中的 UIWebViewWKWebView 或者使用 AVFoundation 播放的在線視頻不受 ATS 的限制。雖然依然需要在審核時進行說明,但這也應該是絕大多數使用了相關特性的 app 的首選。壞消息是這個鍵在 iOS 9 中並不會起作用。

總結一下就是以下兩點:

  1. 對於 API 請求,基本上是必須使用 HTTPS 的,特別是如果你們自己可以管理服務器的話。可能需要後端的同學盡快升級到 HTTPS (不過話說雖然是用 Let‘s Encrypt 的,我一個個人博客都啟用 HTTPS 了,作為 API 的用戶服務器,還不開 HTTPS 真有點說不過去)。如果使用的是第三方的 API,而他們沒有提供 HTTPS 支持的話,需要在 NSExceptionDomains 中進行添加。
  2. 如果你的 app 只支持 iOS 10,並且有用戶可以自由輸入網址進行瀏覽的功能,或者是在線視頻音頻播放功能的話,只加入 NSAllowsArbitraryLoadsInWebContent 或/和 NSAllowsArbitraryLoadsForMedia,並且將組件換成 UIWebViewWKWebView,以及 AVFoundation 中的 player 就可以了。如果你還需要支持 iOS 9,並且需要訪問網頁和視頻的話,可能只能去開啟 NSAllowsArbitraryLoads 然後提交時進行說明,並且看 Apple 審核員的臉色決定讓不讓通過了。除了 WKWebKit 以外,另外一個訪問網頁的選擇是使用 SFSafariViewController。因為其實 SFSafariViewController 就是一個獨立於 app 的 Safari 進程,所以它完全不受 ATS 的限制。
  3. 如果你需要使用內網,可以設置 NSAllowsLocalNetworking,而不必擔心 SSL 連接的問題。

另外,當 NSAllowsArbitraryLoadsNSAllowsArbitraryLoadsInWebContentNSAllowsArbitraryLoadsForMedia 同時存在時,根據系統不同,表現的行為也會不一樣。簡單說,iOS 9 只看 NSAllowsArbitraryLoads,而 iOS 10 會優先看 InWebContentForMedia 的部分。在 iOS 10 中,要是後兩者存在的話,在相關部分就會忽略掉 NSAllowsArbitraryLoads;如果不存在,則遵循 NSAllowsArbitraryLoads 的設定。說起來可能有點復雜,我在這裏總結了一下根據 NSAppTransportSecurity 中設定條件不同,所對應的系統版本和請求組件的行為的不同,可以作為你設置這個字典時的參考 (表中使用了 NSAllowsArbitraryLoadsInWebContent 作為例子,NSAllowsArbitraryLoadsForMedia 也同理):

ATS 設定使用的組件iOS 9 HTTPiOS 10 HTTP備註
NSAllowsArbitraryLoads: NO WebView ? ? 默認行為
URLSession ? ?
NSAllowsArbitraryLoads: YES WebView ? ? 徹底禁用 ATS
URLSession ? ? 審核時需要說明理由
NSAllowsArbitraryLoads: NO & NSAllowsArbitraryLoadsInWebContent: YES WebView ? ? 只對網頁內容禁用 ATS
URLSession ? ? 保證 API 的安全性
NSAllowsArbitraryLoads: NO & NSAllowsArbitraryLoadsInWebContent: NO WebView ? ?
URLSession ? ?
NSAllowsArbitraryLoads: YES & NSAllowsArbitraryLoadsInWebContent: NO WebView ? ? 對於 iOS 10,NSAllowsArbitraryLoadsInWebContent 存在時忽略 NSAllowsArbitraryLoads 的設置
URLSession ? ? iOS 9 將繼續使用 NSAllowsArbitraryLoads
NSAllowsArbitraryLoads: YES & NSAllowsArbitraryLoadsInWebContent: YES WebView ? ? 對於 iOS 10,NSAllowsArbitraryLoadsInWebContent 存在時忽略 NSAllowsArbitraryLoads 的設置
URLSession ? ? iOS 9 將繼續使用 NSAllowsArbitraryLoads

該列表是根據 Apple prerelease 的文檔中關於 NSAppTransportSecurityNSAllowsArbitraryLoadsInWebContent 部分的描述作出的。如果您發現這個行為發生了變化,或者上面的列表存在問題,歡迎留言,我會進行更正。

作為參考,這裏將有效的 NSAppTransportSecurity 字典結構也一並附上:

NSAppTransportSecurity : Dictionary {
    NSAllowsArbitraryLoads : Boolean
    NSAllowsArbitraryLoadsForMedia : 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
        }
    }
}

不得不說,Apple 使用自己現在的強勢地位,在推動技術進步上的做的努力是有目共睹的。不論是前幾天強制支持 IPv6,還是現在的 HTTPS,其實都不是很容易就能作出的決定。而為用戶構建一個更安全的使用環境,可能不僅是 Apple 單方面可以做的,也是需要開發者來配合的一件事情。盡快適配更進步和安全的使用方式,會是一件雙贏的事情。

關於 iOS 10 中 ATS 的問題