MySQLのSET NAMESが危険な理由のおさらい

1年くらい前に社内MLに投げた、「MySQLでSET NAMESを使ってはいけない理由」をコピペしてみます。手抜きです、はい。
赤字は注釈です。


今更ながら、「MySQLで SET NAMES を使ってはいけない」の根拠のお話です。

下記のPHPスクリプトでは、入力値を元にSQL文を生成し、検索クエリを投げています。
※sqltestというDBには、カラムnameを持つuserテーブルが存在します。

GETで渡された値はきちんとmysql_real_escape_stringをかけているので、SQLインジェクションは出来ないように見えます。
しかし、http://localhost/sqltest/index.php?name=%95%5c'%20OR%201=1%20--%20にアクセスすると、全部のデータが見えてしまいます。

下にあるPHPスクリプトを、localhost/sqltest/index.php として配置してください。

SET NAMES SJIS を実行すると、MySQLのエンコードがShift-JISになりますが、mysql_real_escape_stringはUTF-8のまま動作します。

16進数で 95 5c 27 20 は、

  • UTF-8: (謎の文字)(バックスラッシュ)(シングルコーテーション)(スペース)
  • Shift-JIS: (表)(シングルコーテーション)(スペース)

になります。

mysql_real_escape_stringは、バックスラッシュとシングルコーテーションそれぞれをエスケープします。

95 5c 5c 5c 27 20
MySQLは、Shift-JISとして動作するので、 (表)(\)(\)(シングルコーテーション)(スペース) と認識します。

つまり、\が一つ余分に入ることで、入力値のシングルコーテーションがエスケープされなくなります。

マルチバイト非対応のエスケープ関数を使うのと同じ理屈で、SET NAMES は危険です。

基本的に文字コード中に5Cが入るShift-JISが危険ですが、他の文字コードでも似たようなことが起こる可能性があります。

mysql_set_charset('SJIS');

なら、mysql_real_escape_stringもShift-JISとして動作するようになるので、安全です。


<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SQLテストページ</title>
<head>
</head>
<body>

<form action="<?php echo $_SERVER['SCRIPT_NAME'];?>">
    <input type="text" name="name" />
    <input type="submit" value="search" />
</form>


<?php
    //DBに接続
    if (! $db = mysql_connect('localhost', 'sqltest', 'sqltest'))
    {
        echo 'CONNECT ERROR';
        exit;
    }
    mysql_select_db('sqltest', $db);

    mysql_query('SET NAMES SJIS');
//  mysql_set_charset('SJIS');


    //SQLを生成
    $name = mysql_real_escape_string($_REQUEST['name']);
    $sql = "SELECT * FROM user WHERE name='$name'";
    echo $sql . '<br />';


    //実行
    if (! $res = mysql_query($sql))
    {
        echo "QUERY ERROR <br />";
        echo mysql_error();
        exit;
    }

    echo "<pre>";
    while ($row = mysql_fetch_array($res)) {
        print_r($row);
    }
    echo "</pre>";
?>

</body>
</html>
Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

baba

ゆとりプログラマー。 高校時代から趣味でプログラミングを初め、そのままコードを書き続けて現在に至る。慶應義塾大学環境情報学部(SFC)卒業。BPS設立初期に在学中から参加している最古参メンバーの一人。Ruby on Rails、PHP、Androidアプリ、Windows/Macアプリ、超縦書の開発などを気まぐれにやる。軽度の資格マニアで、情報処理技術者試験(15区分 + 情報処理安全確保支援士試験)、技術士(情報工学部門)、CITP、Ruby Programmer Goldなどを保有。

babaの書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ