ketyiaの作ってみた

このサイトでは作ってみたことを記事にまとめていきます!

PHPでSQLインジェクション攻撃を体験してみよう!

こんにちは!IT勉強中のKeitaです!

昨今の情報社会にはデータというものが必要不可欠ですね。
特にAI機械学習は、データあっての技術なのでとても貴重なものとなっています!

今回はそんなデータをデータベースから削除したり盗みとったりするSQLインジェクションという攻撃を実際に自分のローカル環境で体験と対策を行っていきます!

※この攻撃自体は犯罪なので、自分のローカル環境以外では絶対やらないでください!

SQLインジェクション攻撃とは?


WEBサイト上の情報をDB上に登録や検索をする際に、不正なSQLコードに組み替えて、データの削除機密情報を盗んだりする等の攻撃です!

被害としては下記があります
(引用:https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_1.html)

「DBD::PgPP」における SQL インジェクションの脆弱性
「Piwigo」における SQL インジェクションの脆弱性
「サイボウズ ガルーン」における SQL インジェクションの脆弱性


とても悪意のある攻撃です。。正直、この攻撃を受けたら信用とかお金とか色々なものを失ってしまうと考えておいた方がいいですね・・

体験してみよう


デモとして、色々な人が意見を書き込める掲示板サイトを想定します!

お題を立てて、それに対して色々なユーザがコメントを投稿するというサイトです。
このサイト内のユーザ情報を削除することを攻撃の目的とします。
サイトは下記の画像のように作成しました。
※データは事前に入れてあります!


又、コメントのキーワードを検索できる機能を付け加えています!
下記の画像のように絞り込み検索をかけることができます。


データベースあたりの処理のソースコードは下記のように書いてあります!

ーーーーーーーーーーーーーーーーー

// 検索ワード = $key (フォームから取得)
if($key === ''){
    $like = '';
}else{
    $like = ' WHERE ds.comment' . ' LIKE "%'. $key .'%"';
}

$db
= new PDO('mysql:host=localhost; dbname=demo', 'root', '');

try{
    $db->beginTransaction();

    $sql = 'SELECT ds.id , l.user_id , ds.comment
            FROM displayusers as ds LEFT OUTER JOIN login as l
            ON ds.id = l.id'.$like.';';
   
    $stm = $db->prepare( $sql );
   
    // SQLを実行する
    $stm->execute();

    // 結果を取得する
    $result = $stm->fetchAll(PDO::FETCH_ASSOC);

    $db->commit();

}catch ( Exception $e ) {
    // XXX エラーメッセージを表示する
    $error_message = 'データベースエラー';
    echo $error_message . $e->getMessage();
}

ーーーーーーーーーーーーーーーーー

さて、このサイトに攻撃を仕掛けていきます!


このサイトのキーワード検索のテキストバーに以下のコードを打ち込みます!
※ユーザ情報は、loginテーブルで管理しています

ーーーーーーーーーーーーーーーーー
"; TRUNCATE TABLE login; -- "
ーーーーーーーーーーーーーーーーー

SELECT文の検索を「”;」でくくり、「TRUNCATE TABLE login;」でテーブルの中身を削除して、「–」で後ろの文をコメント化するコードです。 

打ち込んだら、検索ボタンを押下します!
そうしますと、下記の画像のようにユーザの情報が消えてしまいました。。


ユーザの情報が全部消えて、
誰が書き込んだコメントなのか分からなくなってしまいました!最悪な攻撃ですね。。もし運用しているサイトでこの攻撃がされたと考えたらぞっとします。。

ただこの攻撃は、攻撃者がDBのテーブル情報を知っているという条件があっての攻撃なので、若干難しい攻撃方法だと主観的には思います!

ただ、起こしてはいけない攻撃だということに違いはないので対策を行ていきます!

対策してみよう!


SQLインジェクションは入力された値を直接的にDBの処理に充てるのでなく、値をBIND(関連付け)として値を渡します!そうすることで、SQLを改変させられるのを防ぎます!

データベースの処理を下記のコードに書き換えます!

ーーーーーーーーーーーーーーーーー
$db = new PDO('mysql:host=localhost; dbname=demo', 'root', '');

try{
    $db->beginTransaction();

    // 検索ワード = $key (フォームで取得)
    if($key === ''){
        $sql = 'SELECT ds.id , l.user_id , ds.comment
            FROM displayusers as ds LEFT OUTER JOIN login as l
            ON ds.id = l.id';
       
        $stm = $db->prepare( $sql );

    }else{
        $sql = "SELECT ds.id , l.user_id , ds.comment
            FROM displayusers as ds LEFT OUTER JOIN login as l
            ON ds.id = l.id WHERE ds.comment LIKE ? ;";

        $stm = $db->prepare( $sql );
        $key =  "%" . $key  . "%";

        $stm->bindValue(1,$key);

        // var_dump($key);
        // var_dump($stm);
    }
   
    // SQLを実行する
    $stm->execute();

    // 結果を取得する
    $result = $stm->fetchAll(PDO::FETCH_ASSOC);

    $db->commit();

}catch ( Exception $e ) {
    // XXX エラーメッセージを表示する
    $error_message = 'データベースエラー';
    echo $error_message . $e->getMessage();
}

ーーーーーーーーーーーーーーーーー

では動作確認をしてみましょう!

消されずに済みました!

これでSQLインジェクションを防ぐことができました!
一つの機能を足すだけで、最低限の攻撃が防げるので忘れずに入れるようにしたいですね!

最後に

SQLインジェクションについてまとめてきました!
今回のSQL文では、テーブルの中身を削除するという処理ですので、バックアップを残しておけば何とかなる可能性がありますが、テーブル自体の削除機密情報が見られたとなるとちょっと面倒になったり、シャレにならなくなる攻撃なので、実際に体験しながら学べてよかったと思います!