轉載地址:https://onevcat.com/2016/06/ios-10-ats/
關於 iOS 10 中 ATS 的問題
本文於 2016 年 11 月 28 日按照 Apple 最新的文檔和 Xcode 8 中的表現進行了部分更新。
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),這方面的相關規定和幾個事實如下:
-
默認情況下你的 app 可以訪問加密足夠強 (TLS v1.2
以上,AES-128 和 SHA-2 以及 ECDHC 等) 的 HTTPS 內容。這對所有的網絡請求都有效,包括
NSURLSession
,通過 AVFoundation 訪問的流媒體,UIWebView
以及WKWebView
等。 -
你依然可以添加
NSAllowsArbitraryLoads
爲YES
來全面禁用 ATS,不過如果你這麼做的話,需要在提交 app 時進行說明,爲什麼需要訪問非 HTTPS 內容。一般來說,可能簡單粗暴地開啓這個選項,而又無法找到正當理由的 app 會難以通過審覈。 -
相比於使用
NSAllowsArbitraryLoads
將全部 HTTP 內容開放,選擇使用NSExceptionDomains
來針對特定的域名,通過設定該域名下的NSExceptionAllowsInsecureHTTPLoads
來開放 HTTP 應該要相對容易過審覈。“需要訪問的域名是第三方服務器,他們沒有進行 HTTPS 對應”會是審覈時的一個可選理由,但是這應該只需要針對特定域名,而非全面開放。如果訪問的是自己的服務器的話,可能這個理由會無法通過。 -
對於網頁瀏覽和視頻播放的行爲,iOS 10 中新加入了
NSAllowsArbitraryLoadsInWebContent
和NSAllowsArbitraryLoadsForMedia
鍵。通過將它們設置爲YES
,可以讓你的 app 中的UIWebView
、WKWebView
或者使用AVFoundation
播放的在線視頻不受 ATS 的限制。雖然依然需要在審覈時進行說明,但這也應該是絕大多數使用了相關特性的 app 的首選。壞消息是這個鍵在 iOS 9 中並不會起作用。
總結一下就是以下兩點:
-
對於 API 請求,基本上是必須使用 HTTPS 的,特別是如果你們自己可以管理服務器的話。可能需要後端的同學儘快升級到 HTTPS (不過話說雖然是用 Let’s Encrypt 的,我一個個人博客都啓用 HTTPS 了,作爲 API 的用戶服務器,還不開 HTTPS 真有點說不過去)。如果使用的是第三方的 API,而他們沒有提供 HTTPS 支持的話,需要在
NSExceptionDomains
中進行添加。 -
如果你的 app 只支持 iOS 10,並且有用戶可以自由輸入網址進行瀏覽的功能,或者是在線視頻音頻播放功能的話,只加入
NSAllowsArbitraryLoadsInWebContent
或/和NSAllowsArbitraryLoadsForMedia
,並且將組件換成UIWebView
或WKWebView
,以及AVFoundation
中的 player 就可以了。如果你還需要支持 iOS 9,並且需要訪問網頁和視頻的話,可能只能去開啓NSAllowsArbitraryLoads
然後提交時進行說明,並且看 Apple 審覈員的臉色決定讓不讓通過了。除了WKWebKit
以外,另外一個訪問網頁的選擇是使用SFSafariViewController
。因爲其實SFSafariViewController
就是一個獨立於 app 的 Safari 進程,所以它完全不受 ATS 的限制。 -
如果你需要使用內網,可以設置
NSAllowsLocalNetworking
,而不必擔心 SSL 連接的問題。
另外,當 NSAllowsArbitraryLoads
和 NSAllowsArbitraryLoadsInWebContent
或 NSAllowsArbitraryLoadsForMedia
同時存在時,根據系統不同,表現的行爲也會不一樣。簡單說,iOS
9 只看 NSAllowsArbitraryLoads
,而
iOS 10 會優先看 InWebContent
和 ForMedia
的部分。在
iOS 10 中,要是後兩者存在的話,在相關部分就會忽略掉 NSAllowsArbitraryLoads
;如果不存在,則遵循 NSAllowsArbitraryLoads
的設定。說起來可能有點複雜,我在這裏總結了一下根據 NSAppTransportSecurity
中設定條件不同,所對應的系統版本和請求組件的行爲的不同,可以作爲你設置這個字典時的參考
(表中使用了 NSAllowsArbitraryLoadsInWebContent
作爲例子,NSAllowsArbitraryLoadsForMedia
也同理):
ATS 設定 | 使用的組件 | iOS 9 HTTP | iOS 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 的文檔中關於
NSAppTransportSecurity
和NSAllowsArbitraryLoadsInWebContent
部分的描述作出的。如果您發現這個行爲發生了變化,或者上面的列表存在問題,歡迎留言,我會進行更正。
作爲參考,這裏將有效的 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 單方面可以做的,也是需要開發者來配合的一件事情。儘快適配更進步和安全的使用方式,會是一件雙贏的事情。