iOS9 : App Transport Securityの確認方法

こんにちは、VOYAGE GROUP のコンテンツメディア事業本部で iOS アプリを担当している @TachibanaKaoruです。

そろそろiOS9のリリース時期も間近になってきて、iOS開発者のみなさまもiOS9対応におわれているころと思います。

個人的には、今回のiOS9対応はユーザーの目に見えない部分での対応負担が高いと感じているんですが、なかでも一番大変なのがApp Transport Security。

すべてのネットワークアクセスに影響するので、最悪の場合にはアプリが起動しないということもありえます。 いまのうちにしっかり確認しておきましょう。

photo by Bohman

ATS(App Transport Security) とは

ATS(App Transport Security) とは、iOS9とOS X 10.11から導入されるネットワークセキュリティ対策です。

developer.apple.com

基本的には、アプリとサーバーの間のネットワーク接続をSSLにすることを推奨するというもので、デフォルトの設定では、SSLではないネットワーク接続が失敗となります。 (なお、ATSが適用されるのは、iOS9用にビルドした場合のみであり、iOS8以前用にビルドされたアプリをiOS9で実行してもATSは適用されません。)

SSL以外にも、下記のような細かい条件が指定されてます。

  • サーバーはTLS 1.2以上をサポートする必要がある
  • 暗号化は forward secrecy(対応する暗号化は上記資料を参照)に対応していなければいけない
  • サーバー証明書のFingerprintが、SHA256以上でないといけない。また2048bit以上のRSA鍵か256bit以上のECC鍵を用いている。
  • 適切なTLS証明書を使っている

developer.apple.com

具体的になにをすればいいのか

さて、アプリからアクセスするすべてのサーバーがAppleの推奨するSSL条件に適合していればいいんですが、そうではない場合には下記のうちのどれかを実行する必要があります。

対策 サーバー側の対応 アプリ側の対応
すべてのサーバーの設定をAppleの推奨するSSL条件にあわせる ⚪︎ ×
ATS自体は有効にするが、ATSの除外サーバーを設定する × ⚪︎
ATS自体を無効にして、ATSの有効サーバーを設定する × ⚪︎
ATSを無効にする × ⚪︎

それでは、アプリで実施しているすべてのネットワークアクセスについて、どんなサーバーにアクセスしているのか見てみましょう。

ネットワークアクセスの確認(自分が書いたコードの場合)

まずは、自分のアプリのなかのネットワークアクセスをすべてあらいだしてみましょう。 NSURLConnectionやNSURLSessionなどを使っている場合には、URLを指定してアクセスしているので、どのサーバーにアクセスしているかは一目瞭然ですよね。 (もしRedirectがある場合には、Redirect先のサーバーも確認してください。)

ただし、UIWebViewやWKWebViewを使っている場合には注意が必要です。指定したURLで読み込まれるドメイン以外にも、外部ドメインからよみこまれる画像やスクリプトのサーバー、外部リンク先などのサーバーをすべて洗い出さなくてはいけません。

例えば、広告を貼っているブログサイトを表示する場合には、その広告配信サーバーをチェックしないといけませんし、Flickrの画像をはっているのであれば、Flickrサーバーをチェックしないといけません。

もし、UIWebViewで不特定のURLを開けるようになっていて、すべての接続サーバーをチェックすることが難しい場合には、ATSを無効にするしか有効な方法はないかもしれません。

ネットワークアクセスの確認(外部ライブラリの場合)

さて、自分が書いたコードのネットワークアクセスについては、簡単に確認することができますが、例えばGoogle AnalyticsやCrashlyticsなど、アプリに含まれる外部ライブラリが行っているネットワークアクセスがどのサーバーにアクセスしているのかはどう確認すればいいでしょうか。

オープンソースの場合にはソースコードをよめばどのサーバーにアクセスしているか確認することはできますが、static libraryなどで提供されている場合には難しいですよね。

そんな場合には、アプリでCFNetworkのログをだして確認してみましょう。

CFNetworkとは、Networkアクセスを担当するCore Servicesレイヤのフレームワークです。 通常は意識することがありませんが、UIWebViewやNSURLSessionやNSURLConnectionなどもこのCFNetworkを使ってネットワーク処理を行っています。 CFNetworkのログには、すべてのネットワークアクセスとその結果が記述されるので、外部ライブラリが行っているネットワークアクセスの確認をすることができます。

CFNetworkのログは、通常のNSLogとは少し違う方法で確認することができます。 (下記のドキュメントに記載されています)

developer.apple.com

では、このドキュメントに書かれている方法で、CFNetworkのログをだしてみましょう。 (なお、このログには、通常暗号化されているネットワーク通信の情報も記述されてしまいます。デバッグ時だけに出力するようにしましょう。)

まずは、main.mファイルのUIApplicationMainの初期化の前で、CFNETWORK_DIAGNOSTICSの環境変数を設定します。

この状態でシミュレーターを使ってアプリを実行します。 (ネットワーク通信が発生するような操作を行ってください。) アプリを終了し、Xcodeの「Window」>「Device」メニューを選び、下の画面を開きます。 Installed Appから対象のアプリを選んで、「Download Container」メニューを選ぶと、シミュレーター上で生成されたファイル(xcappdataファイル)をまとめて取得できます。

f:id:toyship:20150831120207p:plain

このxcappdataファイルはパッケージファイルなので、そのまま中身を確認することができます。 適当な場所において、中をみてみましょう。

このファイル中の/AppData/Library/Logs/CrashReporterパスに、ログファイルが生成されています。

ATSによるエラーの場合には、下記のように「kCFErrorDomainCFNetwork Code=-1022」などのエラーが表示されているので、その部分のurlを確認すれば、どのサーバーでエラーが発生しているかがわかります。 (エラー番号は状況によって変わります)

下記の場合には、「http://mytest.jp/mydata.json」のURLがATSに対応していないということですね。

設定ファイルの書き方

さて、もしATSに対応していないサーバーがあり、サーバー側でのATS対応が難しい場合には、アプリの方でATSの設定を変更する必要があります。 具体的には、アプリに含まれるinfo.plistファイルを編集しなくてはいけません。

下記の場合の設定方法を見てみましょう。

  • ATS自体は有効にするが、ATSの除外サーバーを設定する。
  • ATS自体を無効にして、ATSの有効サーバーを設定する。
  • アプリ側でATS自体を無効にする。

ATSを有効にして除外サーバーを設定する場合

もしATS非対応サーバーが限られている場合には、非対応サーバーだけをinfo.plistにいれましょう。

info.plistに下記のような項目を追加します。下記のファイルの場合には、3つの除外サーバーを設定しているので、この3つのサーバーについてはhttpでも問題なくアクセスできます。

上記の設定では、http接続を許容する設定として、NSExceptionAllowsInsecureHTTPLoadsを追加しているだけですが、サーバーの状況によって、他の条件を追加することも可能です。 たとえば、httpsで接続できるけど、TLSのバージョンが古い場合には、NSExceptionAllowsInsecureHTTPLoads ではなく、NSExceptionMinimumTLSVersionを使って許容できるTLSバージョンを設定することもできます。

また、除外設定は、自社サーバーとサードパーティーのサーバーで登録するキーが異なります。 http接続を許容する場合、自社サーバーであればNSExceptionAllowsInsecureHTTPLoadsを設定するのがいいですが、サードパーティーのサーバーの場合にはNSThirdPartyExceptionAllowsInsecureHTTPLoadsで設定するのがよいでしょう。

設定による効果は同じと思われますが、サードパーティーが提供しているサーバーの場合には、より対応が難しいということで、Appleの許容範囲が広がるのでは、と予想されます。

ATSを無効にして有効サーバーを設定する場合

ATS非対応サーバーが多く、一部のサーバーのみがATS対応している場合には、ATS有効サーバーだけを設定することもできます。

info.plistにこの項目を追加します。

ATSを無効にする場合

すべてのサーバーについてATSを無効にしたい場合には、info.plistにこの項目を追加します。

不特定多数のサーバーにアクセスするアプリであれば、事実上これを選択するしかありませんが、セキュリティ的にあまりおすすめできる対策ではありません。

結局どう対応すべきなのか

まずはこれを機会に、自分のアプリのネットワークアクセスをすべてチェックしましょう。

外部ライブラリでネットワークアクセスをしている場合にはそれぞれのリリース元に確認し、もしATS対応ができていなさそうなら除外リストにいれましょう。

ATS対応があまりに遅いようなライブラリやサービスはメンテナンス要員が足りなかったり信頼性が低い可能性があるので、採用を止めることも考えた方がいいかもしれません。

よくわからない・調べている時間がない・対応出来る技術者がいない、などの場合には、info.plistをかえてATSをオフにするしかないかもしれません。 ただ、おそらくApple的にはセキュリティ堅牢度が高いアプリを優先的に紹介すると予想されるので、ASO対策の観点からは、ATSの対応はすすめて行った方がよいでしょう。