インジェクション攻撃、とは言ってもそのインジェクション対象によって影響が異なります。インジェクション攻撃の対象によって2種類、コードとデータ、に分類できます。Webシステムの場合、リクエストのインジェクションを別のインジェクション攻撃と考えた方が解りやすいので、大まかに分類して3種類に分類できます。
インジェクション脆弱性は絶対に避けなければならない脆弱性である、と認識されていると思います。しかし、3種類あるインジェクション攻撃のうちデータのインジェクションに対するリスク認識が極端に甘いように感じています。
※1 Webシステムを前提としていますが、大抵のシステムは「コード」と「データ」のインジェクションを考慮すれば十分である場合が多いです。
※2 そもそもコードを実行する機能そのものに”コード”を実行させるのは”正当な機能”です。eval( $_GET[‘code’] ) など、これらの機能の基礎的使い方間違いは考慮しません。ここでは本来コードではないデータを介するコードインジェクション、例えば eval( ’var = ‘. $myvar. ‘;’) など、及び、データその物で攻撃するデータインジェクションを取り上げています。
コードのインジェクション
コードのインジェクション攻撃は
何らかの命令を直接データに書き込み、開発者が意図しない不正な操作を行う攻撃
と定義して構わないでしょう。
最も危険で絶対に避けたい脆弱性が攻撃者によるコードやコマンドの実行でしょう。このタイプのインジェクションには
- SQLインジェクション
- JavaScriptインジェクション
- OSコマンドインジェクション
などがあります。バッファーオーバーフローを利用したマシン語のインジェクションもインジェクション攻撃の一種と言えます。不正な関数実行もコードのインジェクションと言えるでしょう。
コードのインジェクションのリスクは正しく認識されていると思います。
データのインジェクション
データのインジェクション攻撃は
- 不正なデータを送信し、本来行えてはならないハズの操作や権限を取得する攻撃
と言えます。
任意コード/コマンドをインジェクションされる脆弱性が無くても、データのインジェクション攻撃ができるだけでも十分に困った状況になります。
最も解りやすい例はSQLデータのインジェクションによるDoS攻撃でしょう。LIMIT句のパラメーターに過大な値を与えられるとDoS状態になるシステムは少なくありません。
SELECT * FROM some_table LIMIT 999999999999;
メールヘッダーインジェクションやHTTPヘッダーインジェクションもデータのインジェクション攻撃です。意図しないメールが送信されたり、おかしなサイトに飛ばされたりするのはとても困ります。
C言語の文字列終端は”\0″(ヌル文字)です。しかし、バイナリセーフな文字列型の言語が多数存在します。ヌル文字インジェクションにより、言語とライブラリの文字列の評価を変え、プログラムファイルをアップロード出来てしまう等、プログラマが予期しない結果となる攻撃もデータに対するインジェクションです。
ディレクトリトラバーサルなど、ファイルパスデータにインジェクション攻撃が可能だと不正やファイルの読み込みや不正なファイルの実行が可能になります。これもファイルパスというデータに対するインジェクションです。
プログラム中の変数(=データ)にインジェクションされると困る事になります。少し古い事例だと、PHPのregister globalsやRailsのMass Assignment脆弱性は管理者フラグなどの変数(=データ)を直接インジェクションする攻撃手法です。古い脆弱性で今は気にする必要がない、と感じるかも知れません。しかし、次に紹介する構造を持つデータでは今でも同類の問題を生む原因になっています。
データには構造を持つ物もあります。代表例は配列やJSON、XMLでしょう。こういった構造型のデータにはアクセス権限やアクセス先など、セキュリティ上重要な情報が含まれている場合が少なくありません。こういった情報を持つ構造を持つデータに任意のデータをインジェクション可能だと、管理者権限の乗っ取りなどが可能になってしまいます。
参考: 本来はアプリも丁寧に作られたRDBMSのデータベース並みのデータセキュリティを入力処理の時点で保証すべきです。
リクエストのインジェクション
CSRFやSSRF、再生攻撃がリクエストのインジェクションの代表例でしょう。これもデータのインジェクション攻撃の一種と考えることも可能ですが、対策方法が多少異なるので別種の攻撃と捉えた方が解りやすいと思います。
データのインジェクションが主題なので、ここでは詳しく取り上げません。
インジェクション対策
インジェクション攻撃対策は次のブログに記載しています。
順序が前後しますが、先ずデータのインジェクション対策です。優先する理由は、プログラムは正しいコードとデータの両方が揃って初めて正しく動作するのですが、データの取り扱いが緩いアプリケーションがとても多いからです。
データのインジェクションを防止するにはバリデーションするしかありません。バリデーションは大別して3種類あります。必要なバリデーションを全て行います。
コード(コマンド)のインジェクション対策はコードとデータを確実に分離します。1 この際、出力先のコンテクストに十分な注意が必要です。
出力先のコンテクストは”1つ”とは限りません。複数のコンテクストが別々/多重化されて存在する場合があります。これに注意していないとコード/データのインジェクションを許してしまいます。
「完全なSQLインジェクション対策」では出力時のセキュリティ対策(≒フェイルセーフ対策)に的を絞っていますが、データバリデーションが無いと完全なSQLインジェクション対策は不可能であること理解できると思います。
※ SELECT $this_col FROM $this_table ORDER BY $order_col に含まれる識別子はデータバリデーションするしかセキュアにする方法がない。
リクエストのインジェクション対策は以下のブログを参考にしてください。
インジェクション対策にはバリデーションが欠かせない
一言にインジェクション対策と言っても、コードのインジェクション対策をするだけでは不十分です。データのインジェクション対策が欠かせません。データのインジェクション対策がないセキュリティ対策は”片手落ちの雑なセキュリティ対策”と言えます。
残念ながら”片手落ちの雑なセキュリティ対策”は広く見られます。2017年版OWASP TOP 10のA10では、マイクロサービス化に伴い入力データバリデーションが欠落/不十分であることが原因で多数の脆弱性が生まれているとしています。
データの正しさ(妥当性)のバリデーションはインジェクション攻撃防止のみでなく、そもそもプログラムが正しく動作するために欠かせない必須条件です。バリデーション無し、不十分なバリデーションではソフトウェアのセキュリティは維持できません。
とは言っても、バリデーションは万能薬ではありません。
SQLインジェクション対策としてプリペアードクエリ/プレイスホルダが万能薬でないことと同じで、入力データ対策と出力データ対策の両方が必要です。両方ないとインジェクション攻撃対策として何時まで経っても不十分で”雑なセキュリティ対策”です。2
脆弱性を1つ1つ潰す=ブラックリスト対策
脆弱な箇所を一つ一つ見つけ一つ一つ直す、といった考え方はブラックリスト型(悪い箇所/モノを定義/見つけ禁止する方式)のセキュリティ対策です。
ブラックリスト型のセキュリティ対策は構造的に脆弱です。Railsセキュリティガイドにはセキュリティ用フィルタの作り方について次のように書いています。
ブラックリストではなくホワイトリストに基づいた入力フィルタを実施することが絶対重要です。ホワイトリストフィルタでは特定の値のみが許可され、それ以外の値はすべて拒否されます。ブラックリストを元にしている限り、必ず将来漏れが生じます。
ホワイトリストとブラックリストの考え方は正にこの通りです。3
入力全てをバリデーションする、出力全てを無害化する、といったホワイトリスト型のセキュリティ対策が必要です。これはISO 27000/ISMSでも要求されているセキュアコーディングの原則です。
脆弱なコードだけに着目すると、ブラックリスト型の対策になる上、セキュアなソフトウェアに必須のデータバリデーションを軽視してしまう傾向が強く見受けられます。
本当はセキュアなソフトウェア構造の紹介もしたいのですが、これは別の機会とさせて頂きます。
関連
バリデーション(妥当性検証)はシステム/ソフトウェア/ネットワーク/モノ(物と者/人)に対して行います。それぞれの信頼境界を定義し、そこで検証するのが基本です。
大別すると入力値は3種類しかありません。ホワイトリスト型バリデーションで”妥当な入力+入力ミス”だけに限定するのが基本です。
バリデーションの基本構造はどのアプリケーションでも共通です。この基本構造がないアプリケーションは構造的に脆弱と言えます。
-
- コードが直接インジェクションできてしまう、eval($_GET[‘code’])、のような極端な例はここでは考慮しません。 ↩
-
- 入力/出力データのセキュリティ対策は入り口と出口に過ぎません。ロジックの正しさも欠かせません。全て揃って十分になります。 ↩
- ベストプラクティス的には入力はフィルタリング(受け入れるモノを抽出)するのではなく、バリデーション(受け入れ可能な正しい/妥当な入力データだけを受け入れる = 余計なモノがある場合はリクエスト自体を拒否する)する物です。 ↩
Leave a Comment