【翻訳】《Swift and Cocoa Essentials》Protecting the Secrets of Your Mobile
私は、多くの開発者にとってあまりエキサイティングでないトピックについて話す傾向がありますが、ソフトウェア開発にとって基本的なトピックについて話すことも習慣にしています。セキュリティはその両方を満たしています。私がセキュリティの話をしても、興奮する開発者はほとんどいません。実は、ソフトウェアを開発する際には、セキュリティは常に最優先事項であるべきなのです。
セキュリティの話をする前に、私はセキュリティの専門家ではないことを強調しておきたい。このエピソードでは、私が長年にわたって学んできたことについて述べています。このエピソードで説明されているプラクティスは、自己責任で使用してください。私、 Cocoacasts 、または私の会社は、これらの実践の適用から生じるいかなるクレーム、損害、またはその他の責任にも責任を負いません。
備えよう
あなたは常に、あなたが構築したソフトウェアが侵害される可能性があることを心に留めておく必要があります。もし熟練した攻撃者があなたのアプリケーションに目をつけたなら、彼らはあなたのアプリケーションとそれが保存している秘密を侵害することができます。侵入不可能なソフトウェアを構築したと思い違いをしてはいけません。
アプリケーションが侵害された場合に何が起こり得るかを知り、理解することが重要です。開発者として、(1) "あなたのアプリケーションとそれが保存している秘密が侵害された場合、どのような結果になるのか"、(2) "そのような事態が発生した場合、どのように対応するのか "という 2 つの重要な質問に答えられるようにする必要があります。
アプリケーションを世界と共有する前に、これらの質問に答えなければなりません。あなたが構築しているアプリケーションにとって、答えは短く単純なものである可能性があります。もしあなたが銀行アプリケーションに取り組んでいるのであれば、答えはもう少し複雑になります。
秘密とは何か?
このエピソードは秘密の保護に焦点を当てており、"秘密とは何か?"という問いを提起しています。このエピソードはクライアント、より具体的には iOS 、 tvOS 、 macOS 、 watchOS アプリケーション のセキュリティに焦点を当てていることを強調しておく必要があります。このエピソードでは、サーバー上のセキュリティは取り上げません。それは別の話です。
私はシークレットを、アプリケーションを識別し、アプリケーションに固有の機密情報と定義します。アプリケーションはシークレットを使って、他のサービスとの間で自分自身を識別し、認証します。例としては、 API キー やシークレットがあります。このエピソードの残りの部分では、より一般的なシークレットという言葉を使います。
公的秘密と私的秘密
公的秘密と私的秘密を区別することは重要です。目標は、どちらのタイプの秘密も他の当事者の手に渡らないようにすることです。これらのタイプの秘密の違いは、公開秘密はある程度暴露されることを意図しているということです。漏洩しても大きな問題にはならないはずです。しかし、私的な秘密が漏えいすることは、重大な結果をもたらす重大なセキュリティ侵害です。
Fabric を例に取ってみましょう。 Fabric は開発者に、アプリケーションの Info.plist に Fabric API キー を追加するよう求めています。アップルの App Store からダウンロードしたアプリケーションから Info.plist を抜き出すのは複雑なことではありません。攻撃者がアプリケーションの Info.plist から Fabric API キー を抜き取ったとしても、その影響は軽微です。攻撃者は Fabric にデータを送信できるかもしれませんが、それは不都合であり、起こってほしくないことです。しかし、大きな問題ではありませんし、あなたのアプリケーションのユーザーに害を与えることもありません。私はこの種の秘密をパブリック・シークレットと呼んでいます。ある程度は承知の上で公開されています。
あなたのアプリケーションが支払プロバイダと通信するために秘密を使うなら、話は別です。その秘密は、何としてでも非公開であり続ける必要があります。攻撃者は、あなたに代わって支払プロバイダと通信することはできないはずです。私は、この種の秘密をプライベート・シークレットと呼んでいます。プライベートな秘密は、故意に公開されるべきではありません。
ユーザーデータ
このエピソードでは、ユーザーのデータについては詳しく説明しません。ユーザーのデータを守るには、別のアプローチが必要です。攻撃者がユーザーのデータにアクセスしたい場合、ユーザーのデバイスに物理的にアクセスするか、中間者攻撃を仕掛ける必要があります。
ユーザーのデータを保護するために従うことができる簡単なガイドラインがいくつかあります。私が適用している最初のルールはシンプルです。機密情報は全てキーチェーンに保存します。それがアップル・デバイスで最も安全な場所です。また、ユーザーが作成しアプリケーションに保存するデータは全て暗号化することをお勧めします。 Realm も Core Data もデータの暗号化をサポートしています。
私がこだわる2つ目のルールは、単なる常識です。絶対に必要な情報だけを保存します。ユーザがサインインするときに、ユーザのパスワードをキーチェーンに保存する必要はありません。ほとんどのサービスは、有効な電子メールとパスワードの組み合わせと引き換えに、アクセストークンをクライアントに返します。このアクセストークンは、そのサービスでユーザーを識別し、認証するために使用されます。
アプリケーションは、パスワードではなくアクセストークンをキーチェーンに保存します。アプリケーションは、アクセストークンを要求する以外にパスワードを必要としません。便宜上、キーチェーンにユーザーのEメールを保存することもできます。ユーザがサインアウトし、後でサインインしたときに、Eメールのテキストフィールドがあらかじめ入力されていると便利です。
ユーザーのデータとアプリケーションの秘密の重要な違いは、漏洩した場合に与える影響です。ユーザーのデバイスが何らかの形で侵害され、ユーザーのデータが攻撃者の手に渡った場合、影響を受けるのはユーザーだけです。
秘密を守る
個人的な秘密を保護するための戦略はいくつかあり、そのうちのいくつかはすでにご存じかもしれません。また、それぞれの戦略の長所と短所についても述べます。おそらく最も一般的で、同時に最も安全性の低い解決策から始めましょう。
Info.plist
秘密を保存する場所として非常に一般的なのは、アプリケーションの Info.plist です。これは便利で、多くのフレームワーク、ライブラリ、SDKは、アプリケーションの Info.plist に公開秘密を追加するよう明示的に求めてきます。それはなぜなのでしょうか?
アプリケーションの Info.plist は、アプリケーションの名前、バージョン、 main storyboard の名前など、アプリケーションを構成する情報を格納するのに理想的です。 Info.plist は公開秘密を保存するために使うことができます。これは、プライベートな秘密には当てはまりません。
App Store からアプリケーションをダウンロードし、アプリケーションバンドルの中身を調べ、 Info.plist を取り出すのは簡単です。そのため、アプリケーションの Info.plist にプライベートな秘密を保存すべきではありません。
コード
もう一つの人気のあるオプションは、プロジェクトに秘密をハードコーディングすることです。秘密はコンパイルされ、アプリケーションのバイナリに埋め込まれるため、それを取り出すのはそれほど些細なことではありません。しかし、注意してください。適切なスキルがあれば、誰でもそのような秘密を比較的簡単に取り出すことができます。この戦略を使用することはわずかに安全ですが、個人的な秘密を保存するために使うべき解決策ではありません。
秘密の暗号化
より高度で複雑な戦略は、アプリケーションが使用する秘密情報を暗号化することです。暗号化された秘密は、アプリケーションのバイナリに埋め込むこともできますし、実行時にリモートサービスから取得することもできます。アプリケーションは、暗号化された秘密を使用する前に復号化する必要があります。
アプリケーションのバイナリに復号鍵を含めるか、アプリケーションが実行時にリモート・サービスから復号鍵を取得することができます。どちらの方法も、復号鍵が何らかの方法で公開されるため、攻撃を受けやすいです。
この戦略には、もう一つ、より微妙な問題があります。アプリケーションは暗号化された秘密をメモリにロードすることでしか使うことができません。熟練した攻撃者は、メモリの内容を読み取ることで、メモリ内にある秘密鍵にアクセスすることができます。
この戦略は完璧ではありませんが、アプリケーションの Info.plist に秘密を保存するよりはずっと堅牢です。
秘密のフェッチ
もう一つのより高度な戦略は、アプリケーションのバイナリに秘密を保存しないというものです。魅力的に聞こえますね。そうでしょう?実行時に、アプリケーションはリモート・サービスにその作業に必要なシークレットを要求します。この方法にはいくつかの利点があります。
最も明白な利点は、アプリケーションのバイナリからシークレットを抽出できないことです。もう一つの利点は、シークレットを素早く簡単に交換できることです。もし秘密の一つが漏洩したらどうなるでしょうか?秘密はアプリケーションのバイナリに埋め込まれているわけではないので、それを破棄して新しいものに置き換えることができます。次にアプリケーションがリモート・サービスにシークレットを要求するとき、アプリケーションは新しいシークレットを送信します。
これらのサービスのほとんどはかなり高度で、興味深いオプションがいくつもあります。各クライアントに異なるシークレットを発行することも可能です。これにより、秘密が漏洩した場合のリスクを制限することができます。
ほとんどのサービスでは、セキュリティ侵害の原因を追跡するための詳細なログを保持しています。また、有効期限が限定されたシークレットを発行することも可能で、セキュリティ侵害の可能性と結果を大幅に減らすことができます。
この戦略は魅力的ですが、前の戦略と同じ問題を抱えています。アプリケーションはタスクを実行するために秘密を使用します。熟練した攻撃者は、メモリにある間、メモリの内容を読むことで、秘密にアクセスすることができます。
ブローカーの利用
先の戦略には、多くの説得力のある利点があります。アプリケーションのバイナリにシークレットを含めないことで、シークレットが漏洩したときに簡単に置き換えることができます。最後に紹介するオプションは、先ほどの戦略をさらに一歩進めたもので、私が最も気に入っているオプションです。
最良の戦略は、アプリケーションからプライベートな秘密を隠すことだということに同意していただけると思います。そうでしょう?それは素晴らしいと思います。問題は、"それがどのように機能するか?"です。
この選択肢を例で説明しましょう。あなたが作っているアプリケーションは、サードパーティのサービスに通知する必要があります。サードパーティ・サービスは、あなたのアプリケーションがリクエストごとに何らかのシークレット、例えばアクセストークンで認証することを期待しています。アプリケーションがそのシークレットにアクセスできない場合、どのようにしてそれが可能になるのでしょうか?
答えは驚くほど簡単です。アプリケーションはブローカーとして機能するサービスを使います。ほとんどのアプリケーションはバックエンドからデータを取得します。そのバックエンドがブローカーとして機能することができます。アプリケーションはバックエンドに通知し、バックエンドはアプリケーションに代わってサードパーティ・サービスに通知します。
この方法にはいくつかの利点があります。先ほどの方法と同様に、漏洩したシークレットを交換するのは迅速で手間がかかりません。アプリケーションはシークレットについて知らないので、シークレットが漏洩した場合でもアプリケーションを更新する必要はありません。
しかし、それだけではありません。アプリケーションは、通知するサードパーティ・サービスの詳細を一切公開しません。攻撃者は、アプリケーションがどのサードパーティにデータを送信しているのか知りません。攻撃者は送信されるデータを読むことができ、サードパーティのサービスにデータを送信することさえできますが、アプリケーションがどのサードパーティのサービスに通知しているかは知りません。攻撃者はシークレットにアクセスする手段も持っていません。ブローカーだけがシークレットにアクセスし、使用することができます。
このソリューションがより高度で、バックエンドを必要とすることは認めざるを得ませんが、そのメリットは投資に十分見合うものです。
パーミッション
プロジェクトに一人で取り組んでいるのであれば、コミュニケーションは問題ではありません。大小にかかわらず、チームで仕事をする瞬間から、ミスコミュニケーションがセキュリティの問題につながらないようにすることが重要です。どういう意味でしょうか?
あなたが取り組んでいるアプリケーションが、サードパーティのサービスとやりとりする必要があるとしましょう。そのためには、例えば API キー などの公開秘密が必要です。あなたはシークレットを作成するのに必要な権限を持っていないので、チームの誰かにシークレットの作成を依頼します。あなたはシークレットを受け取り、サードパーティ・サービスの指示に従って統合を行います。
多くのサービスでは、特定のシークレットを使用して実行できるアクションを制御するためにパーミッションを使用します。あなたのチームメイトがくれたシークレットは、読み取りと書き込みが可能なプライベートなシークレットであることが判明しました。これは、プライベートな秘密を、あたかもパブリックな秘密であるかのように保護していることを意味します。
必要なものを注意深く伝え、与えられたものが合意したものであることを確認することが重要です。明確なコミュニケーションは、このようなセキュリティの問題が本番環境に入るのをしばしば防ぐことができます。
文書化
私は、アプリケーションが使用する秘密を文書化し、チームメンバー全員がその文書にアクセスできるようにすることを強く推奨します。セキュリティは共有責任です。
アプリケーションがアクセスする全ての秘密について、2つの質問に答える必要があることを忘れないでください。最悪のシナリオに備えて、計画を立てておく必要があります。
【翻訳元の記事】
Swift and Cocoa Essentials
Protecting the Secrets of Your Mobile Application
Discussion