shimxmemo

メモをのこすよ!

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のお話)

 

今やってる案件ではPerlSQL::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"}なんて形で渡ってくる事はないと信じたいものの、念の為、利用箇所を調査する事をおすすめします。