一. 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優良血統繼續為我們進行加密服務
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 加密的,否則可能會在應用審核時遇到麻煩。(編輯注:12月22日,蘋果在其開發者網站上表示將延長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的總體結構,所有鍵都是非必填:
可以看出,所有鍵可以分為兩類:主鍵,這些鍵用來定義 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策略
ATS相關設置對iOS8及以下系統無效
需要解決的問題(iOS 9、iOS10及以上)
app內服務器網絡請求訪問支持https(即一般的請求)
webview內支持任意http訪問
第三方sdk接入與支持http訪問
主要是圍繞info.pilst配置文件作相關的安全ATS策略
Info.plist文件是向操作系統描述應用程序的XML屬性列表,是iPhone應用程序文件夾包含所有重要的Info.plist文件
你可能注意到一些關鍵字像是使用了一些其他關鍵字中的詞但是在前面加上了"ThirdParty"字樣,在功能上,這些關鍵字與不含有"ThirdParty"的關鍵字有同樣的效果。而且實際運行中所調用的代碼將會完全忽略是否使用"ThirdParty"關鍵字。
簡單粗暴的方案:
--------------------------------------------
NSExceptionDomains 的設置方法如下, 比如我們要將 weibo.com 這個域名排除在 ATS 驗證之外,就可以這樣:
注意:每個需添加的域都需要設置此三個屬性。如果請求的網絡圖片是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
代碼實現:
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方式添加白名單
提交審核說明:
必須連接由其他機構控制的服務器,其還不支持安全連接。
必須通過 web 展示來源不一的各種網絡內容,但又不能完全使用NSAllowsArbitraryLoadsInWebContent所管理的類。