SQLインジェクション
SQLインジェクションは任意の「SQL」を実行させる攻撃方法です。SQLインジェクションへの対策が施されていないと、SQLの実行に利用されるフォームの入力値等を通じて攻撃が行われます。
SQLインジェクションを体験
それでは、商品管理画面の在庫数変更フォームに
4, price = 18000, name = 'hacked'
と入力して変更ボタンを押してみましょう。
本来は在庫数を変更するための入力フォームですが、変更できないはずの価格や商品名まで変更されてしまいます。これがSQLインジェクションです。
フォームを改ざん
商品一覧ページに移動し、カートに商品を追加してからカート画面に移動しましょう。
右クリックからChromeの「検証」画面を開き、購入数変更フォームの箇所を表示させます。
<input type="number"
から始まる箇所の「number」の部分をダブルクリックすると編集ができますので
<input type="text"
に変更します。すると、数値入力用のフォームが単なるテキストフォームに変わります。
100, user_id = 1
と入力して変更ボタンを押してみましょう。 該当の商品がカートから消えます。
ログアウトして
- id: sampleuser
- pass: password
でログインしてカートの中身を確認してみましょう。
SQLインジェクションの仕組み
なぜこのようなことが起こったのでしょうか?
cart.phpからカートの購入数更新を行なっている関数を確認してみましょう。
cart.php
function update_cart_amount($db, $cart_id, $amount){
$sql = "
UPDATE
carts
SET
amount = {$amount}
WHERE
cart_id = {$cart_id}
LIMIT 1
";
return execute_query($db, $sql);
}
上記の$amountのところに先ほどの文字列を置き換えてみると
cart.php
function update_cart_amount($db, $cart_id, $amount){
$sql = "
UPDATE
carts
SET
amount = 100, user_id = 1
WHERE
cart_id = {$cart_id}
LIMIT 1
";
return execute_query($db, $sql);
}
となります。本来購入数のみを更新する箇所にも関わらず、購入者のuser_idまで更新されてしまうことになります。
SQLインジェクションによる攻撃の例
SQLインジェクション脆弱性を利用すると、例えば
- ユーザー情報編集ページから管理者権限を取得
- 任意のユーザーでログインする
- 全てのデータを更新 or 削除
などの攻撃を受ける可能性があります。サービス運営者にとって膨大な被害をもたらす可能性の高い攻撃ばかりです。
SQLインジェクションへの対策
SQLインジェクションへの対策は、SQLに利用される文字列のエスケープ処理が基本です。
個別に文字列をエスケープ処理することも可能ですが、プリペアードステートメントを利用して、プレースホルダに値をバインドすることにより自動的にエスケープを行うことが可能です。
変数を直接SQLに埋め込むのではなく、PDOのprepareメソッドを利用して作成したステートメントに値をバインドする形式に書き換えましょう。