C3: 信頼できないデータを検証、エスケープ、サニタイズ、パラメータ化する (Validate, Escape, Sanitize or Parameterize Untrusted Data)

説明

入力バリデーションは、適切にフォーマットされたデータのみがソフトウェアシステムコンポーネントに入ることを確保するプログラミング技法です。インジェクション攻撃がクライアントをターゲットにしている場合 (たとえば JavaScript ベースの攻撃など)、ウェブサーバーは攻撃者が提供したデータをクライアントに転送する前にクォーティングやエンコーディングを実行できます。

インジェクション攻撃は、アプリケーションがデータ入力を実行可能なコマンドと混同して入力バリデーションを忘れたり間違って実装した場合に発生します。たとえば、ウェブアプリケーションがユーザーからの入力として電子メールアドレスを受け付けるとします。電子メールアドレスは期待される「データ」でしょう。そのとき攻撃者はアプリケーションが間違えてこの (想定した) データをコマンドとして実行する方法を探しています。インジェクション攻撃はそれぞれ異なる領域をターゲットとします。

  • 攻撃者がアプリケーションを騙してユーザー入力 (データ) を SQL コマンド (またはその一部) として解釈させると、SQL インジェクション攻撃となります。注入されたコマンドはデータベースサーバー内で実行します。

  • リモートコマンドインジェクション (RCE) は、アプリケーションがユーザーデータとウェブアプリケーションサーバーやホストで実行するコマンドを混同した場合に発生します。サーバーサイドテンプレートインジェクションはアプリケーションサーバー内で実行されるインジェクションのもう一つの例です。

  • JavaScript インジェクションが発生すると、ウェブアプリケーションはユーザーデータを受け入れますが、そのデータをコードとして実行するように強制されます。注入された JavaScript コードは一般的に他のユーザーのウェブブラウザ内で実行されるため、ウェブサーバーを直接攻撃するのではなく他のユーザーを攻撃します。

構文的妥当性と意味的妥当性

アプリケーションは何らかの方法でデータを使用する (ユーザーに表示することを含む) 前に、データが 構文的 かつ 意味的 に (この順序で) 妥当であることをチェックすべきです。

  • 構文的妥当性 はデータが期待どおりの形式であることを意味します。たとえば、アプリケーションはユーザーが何らかの操作を行うために四桁の「アカウント ID」を選択できるかもしれません。アプリケーションは、ユーザーが SQL インジェクションペイロードを入力していると仮定し、(適切なクエリパラメータ化を利用することに加えて) ユーザーが入力したデータの長さが正確に四桁であり、数字だけで構成されていることをチェックすべきです。

  • 意味的妥当性 はアプリケーションの機能とコンテキストの許容範囲内でのみ入力を受け付けることを含みます。たとえば、日付範囲を選択する場合、開始日は終了日より前でなければなりません。

脅威

  • 攻撃者はデータベースのクエリを操作するために悪意のある入力を送信することで、SQL インジェクション脆弱性を悪用して機密データへの認可されていないアクセスを得る可能性があります。

  • 攻撃者はウェブページに悪意のあるスクリプトを注入することでクロスサイトスクリプティング (XSS) を実行して、他のユーザーのブラウザで実行され、セッショントークンや個人情報を盗む可能性があります。

  • 攻撃者はシステムコールや API に悪意のあるコマンドを注入することで任意のコードをリモートから実行して、ターゲットシステムを制御する可能性があります。

  • 攻撃者は想定される長さを超える入力を供給することでバッファオーバーフローエラーを引き起こし、メモリを上書きして任意のコードを実行する可能性があります。

  • 攻撃者は不正な入力や過剰な入力でシステムを圧迫することでサービス拒否攻撃を仕掛け、正規のユーザーがサービスを利用できなくなる可能性があります。

  • 攻撃者はパストラバーサル攻撃を通じて認可されていないファイルやディレクトリにアクセスして、機密性の高いシステムファイルや設定データを流出する可能性があります。

  • 攻撃者は XML ドキュメントに悪意のあるペイロードを挿入して XML 解析の脆弱性を悪用し、情報漏洩やシステム侵害につながる可能性があります。

  • 攻撃者はサーバーサイドのテンプレートエンジンに悪意のあるテンプレートを挿入して、サーバー上でリモートコード実行を実現する可能性があります。

  • 攻撃者は HTTP パラメータ汚染攻撃を通じてアプリケーションを混乱させてセキュリティコントロールをバイパスして、アプリケーションロジックを操作したり、制限された機能にアクセスする可能性があります。

実装

インジェクション攻撃に対する保護は、一般的に多層防御アプローチに基づき、入力フィルタリング、出力エスケープ、堅牢化メカニズムの利用を組み込んでいます。前者二つは実装されるセキュリティ対策にのみ依存し、後者は主にクライアントサポートに依存します。たとえば、XSS に対する保護では、入力から XSS をフィルタリングし、出力データをサーバーサイドでエスケープすることで、使用するウェブブラウザに関係なく XSS を防ぎます。Content-Security-Policy を追加することで XSS を防ぎますが、ユーザーのブラウザがサポートしている場合に限ります。このため、セキュリティはオプションの堅牢化対策だけに依存してはいけません。

悪意のあるデータがシステムに侵入するのを防ぐ

提供されたデータを信用してはいけません。すべてのデータに悪意のあるパターンがないかスクリーニングするか、さらに良い方法として、すべてのデータを許可リストと照合します。

許可リストと拒否リスト

構文バリデーションを実行するには、一般に許可リストと拒否リストとして知られている、二つの一般的なアプローチがあります。

  • 拒否リスト処理または 拒否リストバリデーション は、与えられたデータが「既知の不正」コンテンツを含まないことをチェック試行します。たとえば、ウェブアプリケーションは XSS を防ぐために <SCRIPT> というテキストを含む入力をブロックするかもしれません。しかし、この防御は小文字の script タグや大文字小文字が混在する script タグで回避されるかもしれません。

  • 許可リスト処理または 許可リストバリデーション は、与えられたデータが一連の「既知の正しい」ルールにマッチするかどうかをチェック試行します。たとえば、米国の州の許可リストバリデーションルールは、有効な米国の州のうち一つだけである 2 文字のコードになるでしょう。 許可リスト処理は推奨される最小限のアプローチです。拒否リスト処理はエラーになりやすく、さまざまな回避技法でバイパスされる可能性があり、それ自体に依存する場合には危険です。拒否リスト処理は回避されることがよくありますが、明らかな攻撃を検出するのに役立つことがあります。つまり、許可リスト処理はデータが正しい構文的妥当性と意味的妥当性を持つことを確保することで攻撃対象領域を制限するのに役立つ一方で、拒否リスト処理は明らかな攻撃を検出して、潜在的に阻止するのに役立ちます。

クライアントサイドバリデーションとサーバーサイドバリデーション

セキュリティのために入力バリデーションは常にサーバーサイドで実行します。クライアントサイドバリデーションは機能面でもセキュリティ面でも役立ちますが、簡単にバイパスされます。したがって、クライアントサイドバリデーションはユーザビリティのために行われますが、アプリケーションのセキュリティはそれに依存してはいけません。たとえば、JavaScript バリデーションは特定のフィールドが数字で構成されなければならないことをユーザーに警告するかもしれません。それでも、サーバーサイドアプリケーションは送信されたデータがその機能に適した数値範囲の数字のみで構成していることを確認しなければなりません。クライアントサイドとサーバーサイドの両方のバリデーションを使用するもう一つの利点は、サーバーサイドバリデーションの警告がログ記録され、クライアントサイドバリデーションがバイパスした、潜在的なハッカーの操作を通知できることです。

正規表現

正規表現はデータが特定のパターンにマッチするかどうかをチェックする方法を提供します。基本的な例から始めましょう。 以下の正規表現はユーザー名を検証するための許可リストルールを定義します。

^\[a-z0-9_\]{3,16}$

この正規表現は小文字、数字、アンダースコア文字のみを許可します。また、ユーザー名は 3 文字から 16 文字の長さに制限されています。

注意: サービス拒否の可能性

正規表現を作成する際には注意が必要です。設計が不十分な表現は潜在的なサービス拒否状態 (別名 ReDoS ) を引き起こすかもしれません。さまざまなツールをテストして、正規表現が ReDoS に対して脆弱でないことを検証できます。

注意: 複雑性

正規表現はバリデーションを実行する方法の一つにすぎません。正規表現は開発者によっては保守や理解が難しいことがあります。他のバリデーション方法としてプログラムでバリデーションメソッドを記述するものがあり、開発者によっては保守が簡単になるかもしれません。

予期せぬユーザー入力 (マスアサインメント)

フレームワークの中には HTTP リクエストパラメータをアプリケーションで使用されるサーバーサイドオブジェクトに自動バインディングすることをサポートしているものがあります。この自動バインディング機能によって、変更されることを意図していないサーバーサイドオブジェクトを攻撃者が更新できる可能性があります。攻撃者はこの機能によってアクセス制御レベルを変更したり、アプリケーションの意図したビジネスロジックを回避できる可能性があります。

この攻撃には、マスアサインメント、自動バインディング、オブジェクトインジェクションなど、さまざまな名前があります。

簡単な例として、ユーザーオブジェクトにアプリケーションにおけるユーザーの権限レベルを指定する privilege フィールドがある場合、悪意のあるユーザーはユーザーデータが変更されるページを探し、送信される HTTP パラメータに privilege=admin を追加できます。自動バインディングが安全でない方法で有効になっている場合、ユーザーを表すサーバーサイドオブジェクトがそれに応じて変更されます。

これを対処するには、以下の二つのアプローチがあります。

  • 入力を直接バインドすることは避け、代わりにデータ転送オブジェクト (DTO) を使用します。

  • 自動バインディングを有効にしますが、各ページまたは機能の許可リストルールを設定して、どのフィールドが自動バインドできるかを定義します。

より多くの例が OWASP Mass Assignment Cheat Sheet にあります。

入力バリデーションの限界

複雑な入力フォームの中には「有効」であっても危険なものがあるため、入力バリデーションは必ずしもデータを「安全」にするわけではありません。たとえば、有効な電子メールアドレスに SQL インジェクション攻撃を含むことや、有効な URL にクロスサイトスクリプティング攻撃を含むことがあります。クエリパラメータ化やエスケープなど、入力バリデーション以外の追加の防御策を常にデータに適用する必要があります。

データとコマンドの分離を維持するメカニズムを使用する

悪意のあるデータが入力チェックを通過したとしても、アプリケーションはそれらの悪意のあるデータをコマンドやコードとして実行しないことでインジェクション攻撃を防ぐことができます。この目標を達成するには複数の対策がありますが、そのほとんどはテクノロジに依存します。例を以下に示します。

  • SQL を介してリレーショナルデータベースを使用する際、プリペアドステートメントを利用します。SQL インジェクション攻撃は一般的に、攻撃者が文字列連結によって作成された SQL コマンドから「エスケープ」する入力データを提供できる場合に発生します。プリペアドステートメントを使用することで、コンピュータは入力データをコマンドテンプレートから「エスケープ」できないないように自動的にエンコードできます。

  • ORM を使用する際には、オブジェクトが SQL コマンドにどのようにマップされるかを把握してください。その間接層が一般的な SQLi を防ぐかもしれませんが、特別に準備された攻撃は依然として実行可能です。

  • サーバーサイドテンプレートインジェクション (SSTI) はサーバーサイドのテンプレートエンジンを使用して、ユーザーに表示されるコンテンツを動的に生成します。SSTI エンジンでは多くの場合、サンドボックスのコンフィギュレーション、つまり限られた数のメソッドの実行のみを許可します。

  • ユーザー入力をパラメータとしてシステムコマンドを実行すると、インジェクション攻撃を受けやすくなります。可能であれば、これを避けるべきです。

JavaScript インジェクション攻撃

特殊なケースとして JavaScript ベースのインジェクション攻撃 (XSS) があります。注入された悪意のあるコードは一般的に被害者のブラウザ内で実行されます。通常、攻撃者はブラウザからユーザーのセッション情報を盗もうとしますが、(サーバーサイドで行うような) コマンドを直接実行しようとはしません。サーバーサイドの入力フィルタリングと出力エスケープに加えて、複数のクライアントサイド堅牢化対策を講じることができます (これらは、サーバーサイドのロジックが関与せず、悪意のあるコードをフィルタリングできない DOM ベースの XSS の特殊なケースからも保護します)。

  • 機密性の高い Cookie を httpOnly でマークして、JavaScript がアクセスできないようにします

  • Content-Security-Policy を利用して、JavaScript ベースの攻撃の攻撃対象領域を減らします

  • Angular のようなデフォルトで安全なフレームワークを使用します

HTML の妥当性確認とサニタイジング

ユーザーからの HTML を (コンテンツを HTML として表現する WYSIWYG エディタや、入力で HTML を直接受け入れる機能を介して) 受け入れる必要があるアプリケーションを考えてみます。このような状況では、バリデーションやエスケープは役立ちません。

  • 正規表現は HTML5 の複雑さを理解するのに十分な表現力がありません。

  • HTML をエンコードまたはエスケープしても、HTML が正しくレンダリングされなくなるため役に立ちません。

したがって、HTML 形式のテキストを解析してクリーンにするライブラリが必要です。HTML サニタイゼーションの詳細については XSS Prevention Cheat Sheet on HTML Sanitization を参照してください。

特殊なケース: デシリアライゼーション時のデータを妥当性確認する

入力形式によっては、非常に複雑であるため、バリデーションではアプリケーションを最低限しか保護できません。たとえば、信頼できないデータや攻撃者が操作できるデータをデシリアライズするのは危険です。唯一の安全なアーキテクチャパターンは、信頼できないソースからシリアライズされたオブジェクトを受け入れないか、単純なデータ型のみに対して限られた容量でデシリアライズすることです。可能であれば、シリアライズされたデータ形式の処理は避け、JSON などの防御しやすい形式を使用すべきです。

それが不可能であれば、シリアライズされたデータを処理する際に一覧のバリデーション防御を検討してください。

  • シリアライズされたオブジェクトの完全性チェックと暗号化を実装して、敵対的なオブジェクトの作成やデータ改竄を防ぎます。

  • オブジェクト作成前のデシリアライゼーション時に厳密な型制約を適用します。一般的にコードは定義可能なクラスのセットを期待しています。この技法のバイパスが実証されています。

  • デシリアライズするコードを分離して、一時コンテナなど、非常に低い権限の環境で実行するようにします。

  • 受信タイプが予期したタイプではない場合や、デシリアライゼーションで例外がスローされる場合など、セキュリティデシリアライゼーション例外と失敗をログ記録します。

  • デシリアライズするコンテナやサーバーからのネットワーク接続の送受信を制限または監視します。

  • デシリアライゼーションを監視し、ユーザーがデシリアライズし続けた場合に警告します。

防止される脆弱性

参考情報

入力バリデーションについて:

ツール

入力バリデーションの支援:

インジェクション攻撃のテスト:

堅牢化の支援:

Last updated