SQLインジェクション,XSSについて

こんにちは。hacknoteのj.kushiyamaです。

今回学習したことの一部としてSQLインジェクションおよびXSSを紹介したいと思います。

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

MySQLの仕組みを悪用して意図しないSQL文を実行することをいいます。

パスワード認証

user_infoにはユーザーの名前username、パスワードuserpassが入っているとします。
ログインフォームから、次のようにしてユーザー名、パスワードが変数に格納されるとします。

$username = $_POST["username"];
$userpass =  $_POST["password"];

この組を用いて、次のSQL文でログインできるかできないかどうかをチェックします。

SELECT * FROM user_info WHERE name = '$username' AND password = '$userpass';

usernameとしてuser1,userpassとしてuser1が登録されているとします。通常はこの組を入力しますが、悪意のあるユーザは次のような入力を行います。

$username : user1
$userpass : ' OR 'A' = 'A

$userpassに上のような入力をするとwhere句の条件が常に真となることがわかります。(実際にusernameとuserpassに上の値を代入するとわかります。)
where以下の文章は以下のようになります。

WHERE name = 'user1' AND password = '' OR 'A' = 'A';

対策

プレースホルダを用いてこのような入力があってもログインを防ぐことができます。
プレースホルダとは

SELECT * FROM user_info WHERE name=? AND password=?

のようにパラメータ部分をあらかじめ?のような記号で示しておき、あとから機械的に値を割り当てるというものです。 下のログインフォームの例を見るとよく分かると思います。

XSSとは?

Cross Site Scriptingの略で、formなどから他人のwebサイトへ悪意のあるスクリプトを埋め込むことをいいます。
CSS(htmlで用いられるもの)と区別するためにXSSと表記します。

対策

phpの場合、htmlspecialchars関数を利用すると良いです。htmlspecialchars関数はhtmlで特別な意味を持つ記号(&,<,>など)そのものの値を取得します。

SQLインジェクション,XSSの対策を行ったログインフォームの例

if(isset($_POST["login"])){
                $username = htmlspecialchars($_POST["username"],ENT_QUOTES,"UTF-8");
                $password = htmlspecialchars($_POST["password"],ENT_QUOTES,"UTF-8");
                try{
                $dbh = new PDO('mysql:dbname=form;host=localhost','root','');
                } catch (PDOExceotion $e){
                        exit('データベースに接続できませんでした'.$e->getMessage());
                }
                $sql = "SELECT * FROM user_info WHERE name=? AND password=?";#プレースホルダ
                $stmt = $dbh->prepare($sql);
                $stmt->execute(array($username,$password));#値の割当
                $data = $stmt->fetch(PDO::FETCH_ASSOC);
                if(!empty($data)){
                $logged_in=true;
                echo "ログイン成功";
                }else{
                $logged_in=false;
                echo "ログイン失敗";
                }
        }
?>

<!doctype html>
<html>
        <head>
        <meta charset="UTF-8">
        <title>login form</title>
        </head>
<body>
        <form id="loginform" name="loginform" action="<?php print($_SERVER['SCRIPT_NAME']);?>" method="POST">
        <legend>ログインフォーム</legend>
        <label for="username">ユーザ名</label>
        <input type="text" id="username" name="username" value="" />
        <br />
        <label for="password">パスワード</label>
        <input type="password" id="password" name="password" value="" />
        <br />
        <input type="submit" id="login" name="login" value="ログイン" />
        </form>
        <?php if($logged_in):?>
                <?php echo "こんにちは".$username."さん";?>#htmlspecial関数を用いたものを表示することに注意.
        <?php elseif (!empty($username)):?>
                <?php echo $username."さんが見つかりませんでした。入力情報を確認してください";?>
        <?php endif;?>
</html>