Json.pm+SQL::AbstractでもJSON SQL Injectionは起きるよ
前置き
JSON SQL Injectionが話題になっていますね。
参照)
不正なJSONデータによるSQL Injectionへの対策について (Json.pm+SQLクエリビルダー) — Mobage Developers Blog
Kazuho's Weblog: The JSON SQL Injection Vulnerability
(英文にて)
JSON SQL Injection、PHPならJSONなしでもできるよ | 徳丸浩の日記
(PHPのお話)
今やってる案件ではPerlでSQL::Abstractを使っていて、多分同様の事が起こるだろうけど、一応試してみました。
環境
$ perl --version This is perl, v5.8.8 built $ perl -MSQL::Abstract -e 'print $SQL::Abstract::VERSION . "\n"' 1.60
分かっちゃいるけど古くからの案件だからなあ…
結果
やっぱり起きました。
確認用コード
はるぷさんの丸パクリだけれども
use strict; use warnings; use JSON; use SQL::Abstract; #ユーザ入力の取得 my $json = $ARGV[0] || '';# {"name":"xxxxxx"}のような形式を想定 my $user_name = decode_json($json)->{"name"}; #SQL文の生成 my $builder = SQL::Abstract->new(); my ($sql, @bind) = $builder->select( "table_name", "*", {"name" => $user_name} ); print "SQL文: ".$sql."\n"; print "変数: ".join(",",@bind)."\n";
で、実行
実行結果
$ perl ./jsonsql_injection.pl '{"name":{"injection" : "hoge"}}' SQL文: SELECT * FROM table_name WHERE ( name INJECTION ? ) 変数: hoge $ perl ./jsonsql_injection.pl '{"name":["hoge", "fuga"]}' SQL文: SELECT * FROM table_name WHERE ( ( name = ? OR name = ? ) ) 変数: hoge,fuga
ああ…やっぱり。
一般的な1=1とかも簡単にできちゃうよ…。
対策
SQL::Abstractの場合、対策としては、はるぷさんの記事の「対策例2 (型チェック)」か「対策例3 (変換)」になります。
対策例2は省きますが、対策例3を試すと
#実行結果 $ perl ./jsonsql_injection_fix3.pl '{"name":{"injection" : "hoge"}}' SQL文: SELECT * FROM table_name WHERE ( name = ? ) 変数: HASH(0x75fd4e0)
というようになります。
まとめ
たとえばですよ、あるプラットフォームが提供している、戻り値がJSONのユーザー情報APIを元に、SQL文を作成、DBから取得した情報を表示しているとします。
ユーザーがWHERE句で使うパラメータに{"injection" : "hoge"}なんてつけてて、それがそのまま渡ってきた日には、それを元にSQL文を作成している所は全滅ですね。
コケるだけならまだしも、他のユーザー情報など本来意図しない情報がごそっと表示されちゃった日には…シャレになりません。
さすがにそのまま{"injection" : "hoge"}なんて形で渡ってくる事はないと信じたいものの、念の為、利用箇所を調査する事をおすすめします。