カテゴリ: セキュリティ
JavaScriptによるXSS脆弱性という話も出てきているので、その辺りの知識を仕入れるべく「Ajaxセキュリティ」という本を読んでみた。内容的には脆弱性がある前提での攻撃方法の解説が大きな割合を占めているので、防御方法の方を期待している人にとってはちょっとまどろっこしい。結局のところAJAXアプリケーションであっても脆弱性の原因はXSSやSQLインジェクションなどのメタ文字の不適切な取り扱いが大部分を占めるので、防御方法の説明はちゃんとエスケープしろで終わってしまうのだから仕方がないのかもしれない。とはいえ、FLASHのクロスドメインスクリプティング機能の迂闊な使用、JSONデータの保護、サードパーティ製のウィジェットが使えるポータルサイトでの防御などの部分は興味深い。
おおむね良い本ではあるのだが、P.269「第9章 オフラインAjaxアプリケーション」のパラメータ付きSQLクエリを使うべしという説明の中の以下の部分が気になった。
WHERE句における条件文の数が不定の場合も、パラメータ付きのクエリは使用できません。この問題が最も良く発生するのは、Webサイトの検索機能においてユーザーが可変個の検索条件を指定できる場合です。
〜略〜
開発者としては、WHERE句に入る条件の数が事前には分からないので、正しい数の?プレースホルダをあらかじめ設定して、パラメータ付きクエリ文字列を作成することはできません。この問題は、複雑なストアドプロシージャによって解決するのが普通です。しかし、SQLiteはストアドプロシージャをサポートしません。そのため開発者は、ユーザーが検索する条件に基づき、アドホックSQLクエリを動的に組み立てるしかありません。
そんなことはない。パラメータ付きクエリ文字列を動的に組み立てれば、アドホックSQLクエリを動的に組み立てるということは避けられる。たとえば同書でパラメータ付きクエリ文字列ではできないクエリの例として挙げられているSELECT * FROM Articles WHERE content LIKE '%Ajax%' AND content LIKE '%offline%' AND content LIKE '%security%'
といったAND検索は以下のように処理できる。
var keywordList = ["Ajax", "offline", "security"];
var sql = SELECT *FROM Articles;
var conditions = [];
var params = [];
for each (keyword in keywordList) {
conditions.push("content LIKE ?");
params.push("%" + keyword.replace(/%/g, "%%") + "%");
}
if (conditions.length > 0)
sql += " WHERE " + conditions.join(" AND ");
}
do.execute(sql, params);
この程度の処理だと % を %% に変換するついでに ' を '' に変換することで済ませたくなるが、自前でエスケープしていないところに意義がある。検索条件に数値や真偽値などが混ざってくれば、パラメータ付きクエリ文字列を使う利点が見えてくるだろう。餅は餅屋にまかせるべきなのだ。
同書の説明からすると、ストアドプロシージャを使えば少なくとも動的にSQLを生成することは避けられそうな感じを受けるが、実はそうでもない。ストアドプロシージャの利点はSQLが地の文として普通に書けるというところにあるが、この例のように発行するSQLが固定ではないない場合は、結局文字列として組み立ててから改めてクエリーを発行するしかない。やっていることはパラメータ付きクエリ文字列や、アドホックSQLクエリを動的に組み立てることと同じで、結局はどこでそれをやるかの違いしかない。ストアドプロシージャを使えばSQLインジェクション攻撃への対策になるような説明を見ることもあるが、脆弱になる度合いは変わらないのである。