<前の日記(2006年10月29日) 次の日記(2006年11月15日)> 最新 編集

高木浩光@自宅の日記

目次 はじめに 連絡先:blog@takagi-hiromitsu.jp
訪問者数 本日: 1386   昨日: 6103

2006年11月04日

駄目な技術文書の見分け方 その1

はてなブックマークのホッテントリを見ていたところ、300を超えるユーザに登録された以下の記事があった。

また上野宣か。顔見知りなのでズバリいくことにする。

しかし、その対策はまだ本当に理解されていないように思える。

へえ。

終わりの方を見てみると、

Webアプリケーションの対策

  • 入力値のSQLの特殊文字を適切にエスケープ
    入力値=プログラム(プロセス)に外部から入ってくるもの
  • シフトJISの場合には1バイト文字を整理
  • SQLの記述をなくすためにO/R(Object/Relational)マッピングを活用
  • 攻撃者に役立つ情報を与えないために、不要なエラーメッセージ(データベースが出力するエラーなど)の表示を抑止

対策に「準備された文」(prepared statement) のことを書かないのは、どういうつもりなわけ?

「入力値をエスケープ」だあ? いまだにサニタイズ脳から抜けられないのかね君は。「サニタイズ」って書かなきゃいいってもんじゃない。言っていることはサニタイズそのものなんだよそれは。どうして入力値だけをエスケープするわけ? SQL文に埋め込むところで全部するよう解説しろって言ってるのに*1、まだわからんのかね。

戻ってみると、

この問題の対策としては、入力値には半角英数字のみを許可するよう制限する方法や、以下の例のようにSQLで使える特殊文字をエスケープして対処するという方法が一般的になっている。

そんな方法が「一般的になっている」なんて書くなって。そんなのは、はじめっから間違ってるって書くべきこと。

この対策自体の方向性は正しいのだが、SQLインジェクションを理解していないため、対策が漏れている場合がある。

「方向性は正しい」と言いながら「理解していないため」というのはどういう了見なわけ? 「方向性」って何? 方向性からして間違ってるんだって。

■セカンドオーダーSQLインジェクション

SQL インジェクション対策として、入力値を適切にエスケープするという対策を行うが、この「入力値」が何なのか間違えていたり、チェックが漏れている場合がしばしば見受けられる。また、HTMLを生成する段階でエスケープすればよいと考えている人も見受けられるが、それも間違いである。

「入力値が何なのか」なんてぜんぜん考えなくていいっての。「チェックが漏れている」? どこでチェックするの? 入力からSQL文までのデータフローパスのどこかでとでも言うのかい?

「HTMLを生成する段階でエスケープすればよいと考えている人」って何それ? HTML? むりやり勘違い例を捏造してどうすんの? 「SQL文を生成する段階でエスケープすればよい」が正しいのをわかってて、わざと違えているわけ?

フォームに入力可能な部分だけが対策個所ではない。不正な入力の可能性を考える必要があるのは、GETやPOSTなどのクエリーやCookieの値、 HTTPヘッダなど、HTTP経由で送られてくるもの“すべて”と、それに加えてデータベースやファイルなどに保存されたデータを呼び出す際にも対策を怠ってはならない。ここに問題があると、セカンドオーダーSQLインジェクションと呼ばれる脆弱性を持つことになる。

ほら出た。ハッカー様の出番ってわけだね。利権構造ですかこれは。本当の解決方法を教えると出番がなくなるってか?

セカンドオーダー云々なんてどうでもいいの。普通の開発者は覚えなくてよい用語。これは攻撃手法の用語であって、間違った方向性の対策がされているときにのみ意味のある話で、はじめから正しい対策を理解すればよいだけの話。

SELECT name FROM user where uid = '$uid' AND age > $age

このSQLに渡される$uidと$ageの特殊文字は、適切にエスケープされているとしよう。

おいおい、「$age」を「'」で括っていない段階で「$age」が「適切にエスケープされている」って何言ってんの? 「'」をエスケープするという概念が生ずるのは「'」で括っている中においてだってことが、まだわからないのかね。

この問題は、ageの値がシングルクオーテーションで囲われていなかったことが原因である。以下のように囲われていれば、この問題は起きることがない(もちろん、数値以外は受け付けないという前段階の処理も欲しい)。

SELECT name FROM user where uid = '$uid' AND age > '$age'

「囲われていなかったことが原因である」と簡単に言うが、なぜ囲われていなかったのかについては言わないの? 数値フィールドを文字列で比較するとSQLではどうなるの? 文字列が数値に自動変換されるのはSQLの仕様なの? それとも実装依存でたまたま動作するの?

「(もちろん、数値以外は受け付けないという前段階の処理も欲しい)」ってのは何なの? SQLインジェクション対策として言ってるのか、それとも別の話をしているの? 他の人がこの問題への対策にその手のことを書いてるから、なんとなく書かないとまずいと思った?

■マルチバイト文字の問題

(略)

PHPならばaddslashes()といった関数を使って、フォームから受け取った入力値に含まれる「'」を「\'」と置換するなどの処理をしてSQLインジェクションによる攻撃を回避しようとするかもしれない。(略)

ポイントとなるのは「\x97'」の部分で、これの「'」をエスケープするために「\'」と置換すると「\x97\'」となる。(略)

\x97\x5C\x27 → 予'

こんなのは PHPのバグでしょ。エンコーディングがShift_JISの文字列を addslashes() するときに、Shift_JISとして処理していない addslashes() のバグ。なぜそれを言わないで、Webアプリプログラマの責任であるかのように書くわけ?

そして結論部分はこう。

また、どれも1つだけで決定的な手段というわけではないので、対策の際には併用してセキュリティレベルを高めることをお勧めする。

出た。「ぼくちゃんよくわからないから、とりあえず併用せよって解説しとけばいいよね」ってか?

SQL文の作成を正しく行うという「1つだけ」の方法で「決定的手段」なのに、なんで併用とか言い出すわけ? たくさんのSQL文があるときに漏れが生じるからということが言いたいなら、そう書けばいい。

去年4月のときにも似たようないい加減なことを書いていたよね。

  • 「ぼくはまちちゃん」 ——知られざるCSRF攻撃, 上野宣, @IT, 2005年4月27日

    この方法は簡単に実装できて比較的効果の高い方法である。しかし、リファラー情報はリクエスト発信者が自由に発行できる情報であるので、偽装されてしまう恐れもあり100%防ぐといった効果はない。

「100%」て何? 攻撃を防ぐ話をしているのだから、防げないなら対策じゃないでしょ。(しかも、CSRFの文脈でRefererは偽装できないと言ったのに、まだ直してないね。去年会ったときに、「直します」って約束してたよね?)

マスコミの記事でよく見かける表現に、「完全に○○ないわけではない」というものがあるが、これは断定できないことを言うときの逃げ口上だってことを知っておいたほうがよい。マスコミには許されるが、技術文書には許されない。技術文書なら、前提を明らかにした上でその前提の上で何が言えるかを書くのであって、例外があるなら例外を書くようにする。

セキュリティの解説で「どれも完全じゃないからいろいろやっておこう」という表現が出てきたら、その著者は信頼するに値しないと判断してよい。書いてる当人がわかっていないから、問題を整理できていないから、そういう表現が出てくる。


<前の日記(2006年10月29日) 次の日記(2006年11月15日)> 最新 編集

最近のタイトル

2000|01|
2003|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|05|06|07|08|09|10|11|12|
2012|02|03|04|05|06|07|08|09|
2013|01|02|03|04|05|06|07|
2014|01|04|07|09|11|12|
2015|01|03|06|07|10|11|12|
2016|01|02|03|04|06|07|08|10|11|12|
2017|01|02|03|04|05|06|07|10|12|
2018|03|05|06|10|12|
2019|02|03|05|06|07|08|10|
2020|08|09|
2021|07|08|10|12|
2022|01|04|06|12|
2023|03|
2024|03|04|07|11|12|
2025|01|02|03|04|05|06|10|11|12|
<前の日記(2006年10月29日) 次の日記(2006年11月15日)> 最新 編集