シノプシス ソフトウェア・インテグリティ・グループはブラック・ダックになりました 詳細はこちら

close search bar

申し訳ありませんが、この言語ではまだご利用いただけません

close language selection

セキュアなモバイルアプリケーションを開発するためのReact Nativeライブラリの選び方

Black Duck Editorial Staff

Apr 01, 2023 / 1 min read

React Nativeは、Meta社が作成したオープンソース・フレームワークで、ネイティブ機能を失うことなくクロスプラットフォーム・アプリケーションを構築するために使用されています。React NativeのJavaScriptの特性から、このモバイルアプリケーション開発のハイブリッドなアプローチは非常に人気がありました。では、このようなフレームワークを用いた開発におけるアプリケーションセキュリティとは何を意味するのでしょうか?特にモバイル・アプリケーションは、固有のセキュリティの抜け穴や攻撃ベクトルが存在しています。JavaScriptのような透明性の高いものと連携したモバイルアプリケーションを開発することは、新たな課題をもたらすのでしょうか、それとも既存の問題を悪化させるのでしょうか?

そして、ライブラリを選んだ際、私たちは次のように考えているはずです。

「正しく作業を行っているか?」、そしてパフォーマンスについては「アプリケーションの動作が遅くならないか?」と。

もちろん、「アプリケーションを脆弱にしてしまうのではないか?」のようにセキュリティについても考える必要があります。

アプリケーションセキュリティとReact Native

一般的に、アプリケーションは以下のようなセキュリティの原則を念頭に置いて構築されます。

  • 最小権限
  • 多層防御
  • オープンな設計または隠蔽によるセキュリティ
  • アタックサーフェスの最小化
  • クライアントの信頼

モバイルアプリケーションにおけるこれらの原則の実装は、脅威モデルが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つの方法で行う必要があります。

  • データ:いくつかのReact Nativeライブラリでは、アプリケーションがデバイス上のさまざまな場所(データベース、プロパティリスト、共有設定、ログなど)にデータを保存することができます。暗号化をサポートし、データを安全な場所に保存するライブラリを選択してください。暗号化またはハッシュ化を行う場合、暗号化キーなどの関連データを安全な場所に保存する必要があります。一般に、適切なACLコントロールを使用して機密データをキーチェーンに保存すると、より安全であると考えられています。ライブラリがそのような構成を考慮しているかどうかを判断してください。また、これらのライブラリのデフォルト設定には特に注意してください。
  • コード:React NativeにはDOMがありませんが、アプリケーションのスキームやAndroidのエクスポートされたコンポーネント、WebViewの入力などのディープリンクを介して、アプリケーションへの潜在的なエントリーポイントが存在します。ディープリンク経由で呼び出すことができる機能を制限し、エクスポートされた重要なコンポーネントに限定するという「Keep it simple, stupid(構造をできるだけ簡単にせよ)」の設計原則を採用することで、アタックサーフェスを最小限に抑えることができます。また、入力の数を制限し、さらにサニタイズすることをお勧めします。

クライアントの信頼

この原則は、アプリケーションは実行中の環境を選択的に信頼すべきであることを示しています。JavaScriptアプリケーションは、Webであれモバイルであれ、基本的に外部ライブラリの集合体であり、そのほとんどはオープンソースです。そのすべてが完全に安全であったとしても、モバイル・アプリケーションの開発者は、モバイル脅威モデルのルールに従って、ライブラリとそのAPIが適切に実装されていることを確認する必要があります。サードパーティー・ライブラリは、徹底的なモバイルリスク分析の後にのみ使用する必要があります。

さらに、モバイルアプリケーションがインストールされているクライアントと、それが通信するサーバーには、相互に信頼できる手段が必要です。多くのアプリケーションでは、証明書の検証と証明書のピン留めによってこれを実現しており、ここで信頼できる証明書がクライアントにインストールされます。また iOSの場合、Application Transport Securityコントロールなど、安全なネットワーク通信のためのルールを事前に定義するメカニズムをアプリケーションに提供します。たとえば、HTTPを介した安全でない通信を許可する構成「NSExceptionallowsInsecureHTTPLoads」は、信頼できるドメインに限定する必要があります。

アプリケーションデータに関しては、アプリケーションはクライアントだけでなくユーザーに対してもゼロトラスト・アプローチに従う必要があります。ユーザーが、機密データを扱う際に安全でない判断を下すかもしれません。たとえば、ユーザーは、キーロギングを実行できるサードパーティーのキーボードをインストールして使用することがあります。このように、コードに特定のチェックを入れることで、アプリケーションはユーザー・データの漏洩を防ぐことができます。たとえば、パスワードのような機密性の高い入力フィールドにはシステムキーボードのみを許可したり、ユーザーが機密情報を端末のクリップボードにコピーできないようにしたりできます。

React Nativeの主なセールスポイントは、「一度学べば、どこでも書ける」ことです。そのため、JavaScriptを介してより多くのネイティブ機能を利用できるようになっています。したがって、React Nativeアプリケーションは多くの場合コンポーネントベースで、外部ライブラリに依存しています。このようなライブラリを使用すると、サーバーとの通信もJavaScriptコードで開始できます。現在では、React Nativeライブラリを介して、証明書のピン留めや生体認証など、クライアントの信頼原則に関連する重要なリスク緩和策を実装することが可能です。

「多層防御」セクションで説明したように、これらのライブラリは、実装と潜在的なデフォルト構成を慎重に分析したうえで選択する必要があります。たとえば、以下のようなことについて確認します。

  • インストールされたクライアント証明書を検証するための証明書ピン留めライブラリのAPIがイベントベースではないこと
  • クリップボードライブラリAPIが、パスワードなどの機密データフィールドに使用されていないこと
  • 「fetch()」などのJavaScriptメソッドを使用したサーバーとの通信がHTTP経由ではないこと
  • 生体認証ライブラリが構成可能なオプションを提供し、複数回の試行が失敗してもデバイスのパスコードを既定としないこと

つまり、端末の設定や構成に特に注意を払ってください。ライブラリのAPIがフェイルセーフであることを確認してください。システム全体(キーボード、クリップボード)にアクセスできるサードパーティーのライブラリ、証明書、ソフトウェアを信頼することは本質的に危険です。通信は、信頼できるサーバーとプロトコル(HTTPS)に制限する必要があります。

Code Sightを使用したAPIセキュリティの構成

React Nativeライブラリを使用してモバイルアプリケーションを構築する場合、多くの機能が外部ライブラリで実装されることがよくあります。したがって、モバイルエクスプロイトが攻撃者にとって容易なものとならないように、賢く選ぶことが不可欠です。ベストプラクティスとして、それらが最新バージョンであること、安全に実装されていること、ネイティブピアとして構成可能なオプションであること、安全でない既定値を利用していないことなどを確認します。

Rapid Scan Static 2022.12.1では、関連するAPIの安全性と構成のチェックがエンジンに組み込まれるため、React Nativeライブラリをこれらの原則に照らして精査できます。公開されているVS CodeおよびIntelliJ用のIDEプラグインCode Sight™は、これらの新しい機能の検証に使用することができます。SynopsysのCoverity®およびBlack Duck®製品をご利用のお客様は、次のメジャーリリースでこれらの機能を利用できるようになります。

Continue Reading

トピックを探索する