(Last Updated On: 2018年11月12日)

インジェクション攻撃には様々な手法があります。メモリ管理をプログラマが行うC言語などではメモリにインジェクションするバッファローオーバーフロー/アンダーフロー、テキストベースのインターフェースではテキストインジェクション(JavaScriptインジェクション、SQLインジェクションなど)があります。

これらのインジェクション脆弱性はなぜ発生するのでしょうか?

今回は「インジェクション対策、基礎の基礎」の話です。

インジェクション脆弱性の原因

インジェクション脆弱性が発生する原理は非常に簡単です。インジェクション脆弱性は

  • 命令とデータの分離

に失敗した場合に発生します。命令とデータとは何でしょうか?

脆弱性が発生する仕組みと対策が単純なSQLを例に解説しますが、この考え方はプラットフォームや出力先に関係なく全ての出力先に利用できます。

命令とデータ

SQLの命令とはSQL文に「意味」を持たせる文字列です。

  • SELECT
  • INSERT
  • UPDATE
  • DELETE
  • UNION
  • WHERE

これらは一部でSQL文として意味を持った文字列全てが「命令」です。

SQL文におけるデータとはSQL文として意味を持たず、SQL文を実行する為に必要となるパラメーターがデータです。データには

  • テーブル名、フィールド名などの識別子
  • クエリ条件などのリテラル

があります。

インジェクション攻撃

SQLインジェクションは「本来データである部分」に「SQL命令」を混入させることで攻撃します。よくあるSQLインジェクションの例(PHP+PostgreSQLの場合)は以下のようなコードです。

pg_query("SELECT * FROM $table WHERE category = $category ORDER BY date $order" );

このコードは$table、$category、$order変数にそれぞれテーブル名、カテゴリ名、ソート順序(DESCまたはASC)が保存されている事を期待しています。プログラマの意図としては$table、$category、$order変数がデータです。

$table、$category、$order変数に「データ」ではなく「命令」が混入すると、SQLインジェクションが可能になります。

例えば、$tableに’buyers; DROP TABLE product; —‘が設定されている場合、実行されるSQL文は

SELECT * FROM buyers; DROP TABLE product; -- WHERE category (以下省略)

になります。このSQL文は文法的に正しいのでデータベースサーバーはSQL文を実行し、productテーブルの削除権限があれば削除します。

この例では、本来は「データ」であるべき$table

  • SQL文を区切る命令である「;」が挿入され
  • 次にテーブルを削除する「DROP TABLE」命令が挿入され
  • 文字列をコメント化する「–」命令が挿入

されています。

$tableで指定されるテーブル名(識別子)のみでなく、$categoryで指定されるパラメーター(リテラル)でも$orderで指定されるSQL語句(SQL命令)に「命令」が混入していてもインジェクションが可能になります。

インジェクション対策の基本は命令とデータの分離

インジェクション攻撃が可能になる原因は「命令とデータの分離」に失敗していることにあります。

pg_query("SELECT * FROM $table WHERE category = $category ORDER BY date $order" );

このコードでは「データとして渡した」変数すべて、「命令」と分離ができていない状態で渡しています。

インジェクション対策はどのような方法でも「命令」と「データ」を確実に分離できれば構いません。

SQLインジェクション対策の場合、

  • エスケープを利用(識別子・リテラルの分離)
  • プリペアードクエリを利用(リテラルの分離)
  • バリデーション(SQL語句の保護)

これらが確実な「命令」と「データ」の分離に必要です。

命令をデータを分離するAPIを利用しても、データが誤って命令と解釈されないエスケープを使っても同じ効果を得られます。

ただし、命令とデータを分離するAPIは全てのテキストインターフェースで用意されているとは限りません。分離はできても「命令」の部分に「データ」を埋め込む事を禁止できないAPIもあります。このため、セキュリティの基礎教育では不完全なAPIより確実なエスケープ・バリデーションを合わせて教える事が不可欠です。

出力対策の3原則 + 1原則

出力対策の3つの役割 – フェイルセーフ頼みはNG

入力データバリデーション

インジェクション対策として忘れがち、というより忘れられている/無視されている対策に入力データバリデーションがあります。出力対策の3原則+1原則の”+1原則”が入力データバリデーションです。入力データバリデーション無しのインジェクション対策はあり得ません。

バリデーションには3種類のバリデーションがある 〜 セキュアなアプリケーションの構造 〜

インジェクション攻撃は3種類ある

まとめ

SQLインジェクションに限らず、全てのインジェクション対策は「命令」と「データ」を確実に分離することで対策可能です。KVS(Key Value Store)がSQLデータベースより安全であるのは、インターフェースレベルで命令とデータを完全に分離しているからです。KVSはテキストインターフェースの命令が存在しません。データを全てAPIで渡すので命令をインジェクションされる余地がありません。
(注:MongoDBインジェクションの様にデータ形式でのインジェクションが可能となる場合がある。KVSでもテキストによる命令がある場合、インジェクションの可能性があることに注意)

「命令」と「データ」の分離はどのようなプラットフォームを利用している場合でも変わらない、共通のセキュリティ対策です。どんな出力先でも

  • 命令とデータが確実に分離できているか?

を意識し、保証すれば安全に出力できます。

基本はとても簡単ですよね!楽しく、セキュアにコーディングしましょう!

参考

テキストインターフェース処理の基本

攻撃可能面の管理 – セキュリティの基本

セキュアコーディングの構造/原理/原則

投稿者: yohgaki