またまた「日経システム構築」ネタで申し訳ないのだが今月号(2005年12月号)の31ページにセカンドオーダーSQLインジェクションという方法がある。
これは、SQLインジェクションを防ぐのに、外部から受け取るパラメータだけ、サニタイジングしたときにおきる。
具体的に、その方法について、以下日経システム構築に書かれているのを紹介すると
(斜体部がそこからの引用で、ふつうの字体はウィリアムのいたずらの説明)
■■ 前提知識
・SQLにおいて、1行コメントを書くには -- をつけるとかける(以下コメントになる)
・文字列は'で囲む
・SQLインジェクション対策として、サニタイジングを行った場合、'はエスケープされ、'を含む文字も登録することができる
■■ 方法
・はじめに admin'-- というユーザー名と、パスワードを新規登録する
→サニタイジングされて、admin'--が、ユーザー登録される
・次に、admin'--のパスワードを変える
外部から受け取る値は、パスワードなので、パスワードだけがサニタイジングされる
ユーザー名は、サニタイジングされないと、SQL文は
update ユーザーテーブル set password='ユーザー設定パスワード'
WHERE username='ユーザー名'
となるが、ユーザー名はadmin'--なので、結局
update ユーザーテーブル set password='ユーザー設定パスワード'
WHERE username='admin'--'
になる。--以下は、「前提条件」により、コメント、つまりこのSQLは、
update ユーザーテーブル set password='ユーザー設定パスワード'
WHERE username='admin'
という、adminのパスワードを変えていることと同じになる
・結局、admin'--に設定したパスワードがadminに設定されてしまい、他人のパスワードを変えられる
というものだそうな
で、その対策として、「すべての箇所でサニタイジングする」っていうのが挙がってたけど、それって、それ以前に、すべての箇所でサニタイジングしないとバグになるんじゃないの?
■■ バグになりそうな例
・もし、メリーチョコレートが、ユーザー登録したら、当然Mary'sにするよねえ。。。ここに、悪意は、何一つない。あたりまえ。
・これをサニタイズすると、その例により
Mary'sで登録される
・メリーチョコレートがパスワードを変えようとすると、上記の例により
update ユーザーテーブル set password='ユーザー設定パスワード'
WHERE username='Mary's'
となり、最後のs'が??となって、登録できない気が。。バグじゃない??
なので、すべてのところでサニタイズしないと、バグになるとおもいます。
というか、ここでの一番の問題は、上記のとおりだとすると、サニタイズでエスケープしている文字は、ほかの文字種と違う(=ほかの文字と同値ではない)わけですから、当然「ブラックボックステストで」サニタイズでエスケープされる文字について、テストされるべきです。
そのとき、当然、ひととおりのシナリオのテストを一貫してテストすべきです。
今のは、そのテストで、はじける例です。
つまり、その文章のうしろに、「ソースレベルで洗い出せ」とかあるけど、それ以前に、ブラックボックステストで、エスケープする文字は、チェックしてるはずで、そういう基本的なテストは、ちゃんとしましょう。
(入力したところだけでなく、その値を使うシナリオぜんぶだよ!)
それと、基本的に、モジュールの引数のエラーチェックっていうのは、モジュールのはじめで、必要分は、やっておくのが無難だと思います。
というのは、そのモジュールだけ、再利用されたとき、(モジュールのはじめで引数チェックをしておかないと)モジュール引数のテストをしないで、組み込んでしまう危険があるから。
あと、こういうSQLインジェクションを防ぐには、新規システムの場合、はじめから入力できる文字を絞ってしまうのがいいと思います。
ユーザーにとって、'や-がユーザー名にいれられなくても、あんまりこまんないかも。
あと、ご意見や、住所欄は、半角で入力されたら、自動的に全角に変換してしまい、半角を入力させないという手もある。。アメリカの人とかはどーすんだよ!と思うかも知んないけど、日本語で書かれてるホームページをみて、そこのフォームから入れているということは、みている画面で、全角に変えられても、問題ないよね(全角は表示できる画面のはず)
入力文字を絞り込めば、テストのときも、その字種についてのチェックが減る場合もある('を入力できなくさせれば、以降のモジュールの'をテストする必要がない)。
なんで、へらせるもんなら、へらしたほうがいいかも
(ただし、現在動いてるものは、もうだめ(手遅れ)だけどね)