セキュアなモバイル・アプリケーションを構築するために、アプリケーション・セキュリティの原則に従ったReact Nativeライブラリをどのようにして選ぶかを紹介します。
作成者:Vineeta Sangaraju、上級リサーチ・エンジニア、Ksenia Peguero、上級リサーチ・マネージャー(Synopsys)
React Nativeは、Meta社が作成したオープンソース・フレームワークで、ネイティブ機能を失うことなくクロスプラットフォーム・アプリケーションを構築するために使用されています。React NativeのJavaScriptの特性から、このモバイル・アプリケーション開発のハイブリッドなアプローチは非常に人気がありました。アプリケーション・セキュリティは何を意味するのでしょうか?特にモバイル・アプリケーションは、固有のセキュリティの抜け穴や攻撃ベクトルが存在しています。JavaScriptのような透明性の高いものと連携してモバイル・アプリケーションを開発することは、新たな課題をもたらすのでしょうか、それとも既存の問題を悪化させるのでしょうか?
ライブラリを選ぶとき、私たちは通常その機能について次のように考えます。「正しく作業を行っているか?」、そしてパフォーマンスについては「アプリケーションの動作が遅くならないか?」と考えます。しかし、「アプリケーションを脆弱にしてしまうのではないか?」など、セキュリティについても考える必要があります。
一般的に、アプリケーションは以下のようなセキュリティの原則を念頭に置いて構築されます。
モバイル・アプリケーションにおけるこれらの原則の実装は、脅威モデルがWebアプリケーションの脅威モデルとは異なるため、若干異なりますが、React Nativeで構築されたアプリケーションではさらに異なります。これらの各原則について、React Nativeがアプリケーションの全体的なセキュリティに与える影響を検証してみましょう。
この原則は、アプリケーションが必須の権限のみを持つ必要があることを指定するものです。Android環境の場合、一般的なモバイル・アプリケーションは、サービスやレシーバーなど、いくつかのコンポーネントで構成されています。これらのコンポーネントは、アプリケーションが機能するためにさまざまな端末のプロセスとやりとりする必要があります。たとえば、音楽ストリーミング・アプリケーションには、音楽をローカル・ファイル・システムに保存するためのサービス・コンポーネントが含まれている場合があります。ただし、このアプリケーションに端末の位置情報やカメラへのアクセスを要求するコンポーネントがある場合は、最小権限の侵害を示す可能性があります。
通常、ネイティブ・アプリケーションでは、ビルドする前に構成ファイルで権限を設定します。一方、React Nativeライブラリを使用すると、アプリケーションは実行時にアプリケーションの権限を読み取って設定できます。必ずしも新しいリスクが発生するわけではありません。ただし、ネイティブ・コードと同様に、React Nativeコードは過度に特権的な権限を要求してはなりません。
この原則は、脆弱性の連鎖からアプリケーションを防御するためのセキュリティのベストプラクティスを指します。Webアプリケーションと同様に、モバイル・アプリケーションも、データの盗難やコードの改竄などの一般的なリスクから保護できます。防御策の例としては、アプリケーションの使用を、ジェイルブレイク(脱獄)していない端末や最新バージョンのOSを搭載した端末に限定する、セキュアでないAPIや非推奨のAPIを避ける、アプリケーションのプロセスにデバッガーを接続できないようにする、などが挙げられます。
最近では、こうした防御策をネイティブ・コードではなくReact Nativeコードで実装するアプリケーションが増えています。これらの防御策がどのように機能するかを理解することが重要です。アプリケーションをジェイルブレイクしていない端末に限定する慣習の導入を検討しましょう。ジェイルブレイク検出ライブラリを選択する際は、使用されているAPIの実装を分析します。その実装は、ブール型の戻り値に依存していますか? もしそうなら、それはイベントベースであると見なされ、特に他の補完的な防御がない場合、簡単に迂回できます。
一般に、典型的なモバイル・リスクから防御するためにReact Nativeライブラリを選択する場合、実装と非推奨のメソッドに注意してください。さらに、アプリケーションのセキュリティに影響を与えるデフォルト値やその他の構成オプションが脆弱性をもたらさないようにすることです。
この原則は、アプリケーションの内部構造の機密性に依存しています。従来のWebアプリケーションでは、いくつかの実装がクライアント側に存在するため、攻撃者がそのロジックを理解し、それを悪用することがより簡単になっています。クライアント側のコードは、攻撃者が簡単に到達できます。クライアント側のコードで何を公開すべきか、何を公開すべきでないかを判断することは、少なくともWebアプリケーションでは非常に簡単です。オープンな設計を取り入れ、クライアント側で必要なものだけを公開し、サーバー側では重要な作業を安全に行うというように、バランスを取ることができます。
しかし、特にReact Nativeのようなハイブリッド・フレームワークを使用している場合、モバイル・アプリケーションはクライアント側(モバイル・デバイス)で重要な作業を行います。では、このオープンな設計の原則に関する推奨は、大目に見るべきなのでしょうか?
はい。モバイル・アプリケーションでは、ロジックとデータ・ストレージをクライアント側に移動する傾向があるため、Webアプリケーションの場合よりも隠蔽性が重要になります。攻撃者は、十分な時間とリソースがあれば、最終的には隠蔽されているものに到達しますが、前のセクションで説明したような特定の防御策を講じれば攻撃を遅らせることができます。
一般的に、モバイル・アプリケーションのバイナリとデータはデバイス上に存在するため、アプリケーションのバイナリのコードを難読化すると、攻撃者がアプリケーションの動作を理解するのが難しくなり、標的型攻撃を阻止することができます。ただし、緩和策はサーバー側で講じる必要があります。また、難読化だけに頼ることが良くない習慣と見なされることにも注意してください。
一般的なReact Nativeアプリケーションでは、ネイティブ・コードとデータに加え、JavaScriptコードもクライアント側に存在します。残念ながら、ネイティブ・コードを難読化する方法がJavaScriptコードに対して有効であるとは限らないため、難読化のためにReact Nativeライブラリを選択する際は慎重に選択してください。React Nativeコードのディレクトリ全体が難読化のために選択されていることを確認します。また、アプリケーションの設計を再検討し、クライアント側で本当に実行する必要があることに優先順位を付けます。アプリケーションは、速度と効率を損なうことなく、リスクの高いロジックやデータをサーバー側に移動させることはできるのでしょうか? データに関しては、APIやサーバー・キーなどの環境変数や定数の管理に役立つReact Nativeライブラリが存在します。ただし、保存されるデータを暗号化するか、データの場所にアクセス制御をかけるかどうかが重要なポイントです。
この原則では、アプリケーションへのエントリー・ポイントの数を制限することを推奨しています。従来のWebアプリケーションでは、アタックサーフェスは入力フィールドとURLパラメータです。モバイル・アプリケーションの場合、アタックサーフェスは、ユーザー入力とアプリケーションが存在するサンドボックスの両方です。サンドボックスとは、アプリケーションが動作する、デバイス上のコンテナ化された場所のことです。アプリケーション・プロセスは、そのサンドボックスに存在するデータにのみアクセスできます。オペレーティング・システムは、サンドボックス化によってアタックサーフェスをある程度まで小さくしますが、これですべてのセキュリティ上の懸念に対処できるわけではありません。脆弱なアタックサーフェスがあったとしても、データが漏洩したり(機密性が低い)、データとコードが操作されたり(インテグリティが低い)する可能性があります。
たとえば、アプリケーションは、高速で応答性を高めるために、ユーザー・データを端末に保存する必要があります。しかし、端末が侵害された場合はどうでしょうか? アプリケーションは、ユーザーの個人情報や資格情報が漏洩するという、最小限ではあるが存在するリスクを受け入れるべきなのでしょうか? ユーザーがより高い権限を持つ管理者だった場合はどうでしょうか? 重要なのは、この情報が端末のどこに保存されているかだけでなく、漏洩を防ぐためにどのような種類のアクセス制御が行われているかを意識することです。また、モバイル・アプリケーションでは、サンドボックスの外からアプリケーションやアプリケーション内の特定の機能を呼び出すディープリンクも可能です。安全に構成されていないと、アプリケーションの機能とデータが危険にさらされる可能性があります。
純粋なネイティブ・アプリケーションと同様に、React Nativeアプリケーションはサンドボックスに限定され、外部の潜在的に悪意のあるアプリケーション・プロセスを寄せ付けないようにすることができます。アプリケーションへの潜在的なエントリー・ポイントが少なく、アタックサーフェスも小さいように見えますが、アプリケーションは依然として中間者攻撃、デバイスの盗難、インジェクションのリスクにさらされている可能性があります。保管時および転送時のデータ保護を支援するライブラリは、最初の2つを軽減するのに役立ちます。インジェクションによるデータ損失やコードの改竄操作については、クロスサイト・スクリプティング(XSS)を検討してください。React Nativeアプリケーションにはドキュメント・オブジェクト・モジュール(DOM)がなく、JavaScriptが実行できるコンテキストがないため、JavaScriptによる攻撃は受けません。SQLインジェクション、パス・インジェクション、コマンド・インジェクションなどのインジェクション攻撃も潜在的なリスクとなりますが、ユーザー端末やアプリケーション全体に与える影響は、その機能の性質と実装によって異なります。React Nativeアプリケーションのアタックサーフェスを最小限に抑えるには、次の2つの方法で行う必要があります。
この原則は、アプリケーションは実行中の環境を選択的に信頼すべきであることを示しています。JavaScriptアプリケーションは、Webであれモバイルであれ、基本的に外部ライブラリの集合体であり、そのほとんどはオープンソースです。そのすべてが完全に安全であったとしても、モバイル・アプリケーションの開発者は、モバイル脅威モデルのルールに従って、ライブラリとそのAPIが適切に実装されていることを確認する必要があります。サードパーティー・ライブラリは、徹底的なモバイル・リスク分析の後にのみ使用する必要があります。
さらに、モバイル・アプリケーションがインストールされているクライアントと、それが通信するサーバーには、相互に信頼できる手段が必要です。多くのアプリケーションでは、証明書の検証と証明書のピン留めによってこれを実現しており、ここで信頼できる証明書がクライアントにインストールされます。また、モバイル・オペレーティング・システムは、iOSの場合、Application Transport Securityコントロールなど、安全なネットワーク通信のためのルールを事前に定義するメカニズムをアプリケーションに提供します。たとえば、HTTPを介した安全でない通信を許可する構成「NSExceptionallowsInsecureHTTPLoads」は、信頼できるドメインに限定する必要があります。
アプリケーション・データに関しては、アプリケーションはクライアントだけでなくユーザーに対してもゼロ・トラスト・アプローチに従う必要があります。ユーザーが、機密データを扱う際に安全でない判断を下すかもしれません。たとえば、ユーザーは、キーロギングを実行できるサードパーティーのキーボードをインストールして使用することがあります。このように、コードに特定のチェックを入れることで、アプリケーションはユーザー・データの漏洩を防ぐことができます。たとえば、パスワードのような機密性の高い入力フィールドにはシステム・キーボードのみを許可したり、ユーザーが機密情報を端末のクリップボードにコピーできないようにしたりできます。
React Nativeの主なセールス・ポイントは、「一度学べば、どこでも書ける」ことです。そのため、JavaScriptを介してより多くのネイティブ機能を利用できるようになっています。したがって、React Nativeアプリケーションは多くの場合コンポーネントベースで、外部ライブラリに依存しています。このようなライブラリを使用すると、サーバーとの通信もJavaScriptコードで開始できます。現在では、React Nativeライブラリを介して、証明書のピン留めや生体認証など、クライアントの信頼原則に関連する重要なリスク緩和策を実装することが可能です。
「多層防御」セクションで説明したように、これらのライブラリは、実装と潜在的なデフォルト構成を慎重に分析したうえで選択する必要があります。たとえば、以下のようなことについて確認します。
つまり、端末の設定や構成に特に注意を払ってください。ライブラリのAPIがフェイルセーフであることを確認してください。システム全体(キーボード、クリップボード)にアクセスできるサードパーティーのライブラリ、証明書、ソフトウェアを信頼することは本質的に危険です。通信は、信頼できるサーバーとプロトコル(HTTPS)に制限する必要があります。
React Nativeライブラリを使用してモバイル・アプリケーションを構築する場合、多くの機能が外部ライブラリで実装されることがよくあります。したがって、モバイル・エクスプロイトが攻撃者にとって容易なものとならないように、賢く選ぶことが不可欠です。ベストプラクティスとして、それらが最新バージョンであること、安全に実装されていること、ネイティブピアとして構成可能なオプションであること、安全でない既定値を利用していないことなどを確認します。
Rapid Scan Static 2022.12.1では、関連するAPIの安全性と構成のチェックがエンジンに組み込まれるため、React Nativeライブラリをこれらの原則に照らして精査できます。公開されているVS CodeおよびIntelliJ用のIDEプラグインCode Sight™は、これらの新しい機能の検証に使用することができます。SynopsysのCoverity®およびBlack Duck®製品をご利用のお客様は、次のメジャー・リリースでこれらの機能を利用できるようになります。