初心者のためのWEBアプリのセキュリティ対策
http://ameblo.jp/yosswi/entry-10028788115.html
うーん、うーん、大筋は間違ってないんだけど、高木先生にサニタイズ脳と言われそう。
まず、入力時のチェックでタグの変換はダメですよ。これは、タグ変換をいらないところでやることによるバグの混入を防ぐためです。タグの変換は出力直前にしましょう。
あくまで、入力時のチェックは、数字しか入ってないかとか、許可されている文字だけで構成されているかとか、文字数が最大文字数を超えていないか、フォーマットが正しいものかといったことしかチェックしないようにしましょう。
これだけで、セキュリティの強度は大きく変わります(当然、許可されている文字に危険な文字が入るとダメなので、これだけではダメですが)。こういったことは、きちんとしたアプリケーションであればやっていて当然のことです。
次に、出力時のチェックで、SQL文の話がありますが、シングルクォートをダブルクォートに変換とありますが、これは、正しくありません。この変換をしてしまうと、問題が発生したり、誤ったデータを使ってしまうことになります。
正しくは、シングルクォート1個(')をシングルクォート2個('')に変換しないといけません。そうしないと思わぬバグが発生します。また、RDBMSによっては(多くのRDBMSが該当しますが)「¥」も「\\」に変換しないといけません。こうしないとSQLインジェクションを起こす危険性があります。
SQLを使うとき一番良いのはバインドメカニズムを使用することです。PHPでも、PHP5ならPDOを使えば標準で使用できます。PHP4の場合はライブラリを別途使わないとダメみたいですが。
但し、バインドメカニズムも万能ではなく、DBと処理系の文字コードが違う場合は問題が発生することがあります。とはいえ、手でエスケープ処理を行うより、漏れが発生しないため、セキュリティの強度はぐっと上がります。
XSS対策としてタグの変換というのだけでは不十分です。リンクにjavascript:alert(document.cookie);と入れると、ポップアップが出るように、タグを使わない方法がいくつもあります。なので、XSS対策は結構面倒です。
そのときそのときに応じたチェックなり、エスケープ処理が必要となります。
また、あげられている3つの方法ではセッションハイジャックは防ぐことは出来ません。
まあ、暗黙の了解で書いていないのかもしれませんが・・・
セッションハイジャックはセッション管理に使用されるセッションIDを盗む若しくは推測して、攻撃する手法なので、セッションIDを推測できないものにするということが対策となります(盗まれないようにという点については、XSS対策やSSLを使うことである程度防げます)。
今あるPHPやJSPといったものではその言語、フレームワークがセッション管理機能を持っているので、そういったものを使っている限りにおいては、まず問題は発生しません。
しかし、独自でセッション管理を実装していると、簡単に推測されたり、問題が発生することがあります。
例えば、ミリ秒単位の現在時刻をMD5でハッシュ化したものをセッションIDとして使用していると、一見すると、ランダムに見えますが、同時にアクセスがあった場合、同じセッションIDが別のユーザに割り振られるなんてことがあるので、こういったものはセッションIDとして使用してはいけません。
とまあ、細かいツッコミを入れてみたけど、確かにプログラムが本職じゃない人にはセキュアプログラミングは難しいかもなぁ。誰でも簡単に安全なプログラムが書けるフレームワークがあればいいのかもね。ま、そういうのは幻想かもしれないけど・・・
セキュアにコーディング
昨日見つけた記事をじっくり読んでみた。
本来の意味でのハンガリアン記法はすごいかもしれない。一般に言われているハンガリアン記法は変数の型を変数名に持たせちゃえというのだけども、本来は、変数名、関数名に状態(意味といった方がいいか?)を持たせるというものだったらしい。
例えば安全だったら接頭辞に「s」を、安全でなかったら、接頭辞に「us」をつけるという言った感じ。
そうすると、こんな感じになる。
usParam = Request.getValue("param");
sParam = sEscape(usParam);
これらは、「=」左辺と右辺で接頭辞が同じであればよいことになるので、正しいコードとして認識しやすい。
output.sWrite(usParam);
output.write(sParam);
また、これらも、安全でない変数を安全な関数で使うか、安全な変数を安全でない関数で使うことが一目瞭然のため、分かりやすい。
ところが、こんな場合は危険なコードとなる。
sParam = Request.getValue("param");
output.write(param);
安全でない変数を安全とみなす変数に代入したり、安全でない変数を安全でない関数で使うことになるため、危険な匂いがぷんぷんするわけだ。
param = sEscape(Request.getValue("param"));
output.sWrite(sParam);
また、こういったものも、2重にエスケープしてしまうという間違いを起こす可能性があるので、危険なコードといえる。
これは何も、セキュアなコーディングに関するだけじゃないと思う。例えば、あるかどうか分からないけど、アプリケーションで複数の文字コードを処理しなければならないとき、SJISだったら「sjis」、EUCだったら「euc」、JISだったら「jis」、UTF8だったら「utf8」のように接頭辞を決めてしまえば、今変数に入っているコードは何か一目瞭然だ。こうすることで、バグの混入を少なく出来るのはすばらしいと思う。
一般に言われているハンガリアン記法は変数の型を表記してしまうけど、これって、コンパイラやツールがチェックしてくれるのであまりうれしくないけど(Cの場合はポインタか実体か一目で分かるのでこれはこれで便利だけどね)、本来の意味でのハンガリアン記法は、その変数、関数がどういった状態なのかというのを一目で分かるのですばらしいなぁ。なんといっても、危険なコードの匂いが、機械的に判断つくというのがいいねぇ。
今度から、ハンガリアン記法使ってみようっと。