Kazuho's Weblog: The JSON SQL Injection Vulnerability について。元記事をはっちゃめっちゃに要約すると

  • SQL::Maker にユーザから受けとったデコード済み JSON をそのまま突っ込むと SQL インジェクションになる場合がある
  • SQL::Maker 側でそういったことが起こらないように strict オプションをつけたから、できればそっち使え
  • 別に SQL::Maker に限らないから気をつけろ

という話っぽい。本来であればユーザ入力をタイプチェックをすべきだけど、クエリビルダレベルでも、脆弱性にならないようにもうちょっと考慮してもいいよねという趣旨かな…

strict モードは非互換なので、既存のコードが動かなくなる可能性があるようです。

Teng での対応

Teng を使っているとデフォルトで SQL::Maker がクエリビルダとして使われるので、同じように危険な場合があります。Teng 0.24 から、クエリビルダのコンストラクタにオプションを渡せるようになったので、以下のように書くと strict モードになります。

my $teng = My::DB->new({
    ...
    sql_builder_args => { strict => 1 }
});

Teng 0.23 以前の場合、このオプションがないので、以下のように自分で sql_builder に SQL::Maker のインスタンスを作って渡す必要があります。

my $teng = My::DB->new({
    ...
    sql_builder => SQL::Maker->new(driver => 'SQLite', strict => 1);
});
既に使っている場合

strict モードつきにしてみて問題なく動くならそのほうがいいですね。非常に単純なクエリは strict モードにしても変わりませんから、

$teng->search('foo', { id => $id })

みたいなクエリしか書いたことねーぞ! って場合、何も考えず strict を有効にして試してみると今後比較的穏かな気分でコードを書けることになります。

そうではない場合でも、あまりに大量にクエリビルダで複雑なことをしているというわけではない限り、 strict を有効にしてコードを書きかえ、検証しなおすべきでしょう。

さらに、どうせコード書きかえるなら根本的に入力のタイプチェックを行うのも考えたほうがいいと思います。


どうしても strict モードを有効にしたくないぐらい複雑にクエリビルダを使いこなしている場合かつ、脆弱性になりそうなコードを書いた覚えがあってヤバいぞという場合、ユーザから受けとる JSON などの構造化データを復号化するところで、一括して再帰的に全ての HashRef, ArrayRef, ScalarRef などを適当に bless することで、ある種の「汚染された」フラグとし、少なくとも SQL インジェクションについては防ぐことができると期待できます。

これは、SQL::Maker が strict オプションが入っていなくても、元から bless された構造化データについては文字列化が走るような挙動になっているためです。

ただ、これはこれでやはり全体的に影響する変更になるので、検証がstrict を入れる場合と同じように大変であり、コードを書きかえる手間の問題ないし、SQL インジェクションのリスクとほかのところで問題がでるリスクを比べた場合に、どうしてもとる1つの手段であって、基本は strict を有効にするように頑張ったほうが生産的かつ安全だと考えられます。

ユーザが構造化データを作れること

ウェブアプリケーション開発者は、普通のHTMLフォームが文字列しか送信できないという、歴史的経緯により無意識に、危険なデータは文字列でしかこないとなんとなく思っている。なのでユーザーが構造化データをつくって送れること自体がうっかり脅威になりえることがある。この手の問題は Perl に限らず Rails でも発生してる。

昨今では JSON をリクエストボディーにしたり、クエリ文字列にルールを与えて (例えば foo[bar]=1&foo[baz]=2 みたいな) 構造化データを受けとれるようにしたりといったことが行われる。これにより、信頼できない構造化データというのが生まれている。

単純なデータ構造でクエリを組み立てるというのは、それ自体が危険なAPI設計といえ、また、入力のタイプチェックをすれば防げる問題なので、それを強制するフレームワークになっているほうが良い、という学びを得られた。

  1. トップ
  2. tech
  3. ユーザ由来の構造化データによるSQLインジェクション
▲ この日のエントリ