キケンなSQLインジェクション

  • 2008/06/26(木) 14:00:00

更新情報

yappoさん、nipotanさん、麻理さんを追加しました!ありがとうございます!!
日本のGeeksがマジ優しすぎて鼻から牛乳><
geek DataBase - ギークデータベース



SQLインジェクション攻撃による不正なデータベース操作を防ぐ

前回の更新後、さっそく秘密コメントやTwitter等で脆弱性を指摘されました><
zapaさん、kidd-number5さん、ほかアドバイスくださったすべての方へ!
とても勉強になりました!ありがとう、ありガ島通信!!!

geekDataBaseに、かの有名なSQLインジェクションの脆弱性がある、という衝撃の事実が判明。
うわさには聞いていたが、まさか自分の身に降りかかるとはっ・・・。
参考:サイト脆弱性をチェックしよう!--第6回:SQLインジェクションの検査方法


// id=数字以外はエラーメッセージを表示 という部分。
これを追加してすっかり満足してたけど、どうやら入れるタイミングがまずいらしい。

7   $sql="select * from geekDB where id = " . $id;
8   $result = mysql_query($sql);


というクエリ実行後に「そういえばidは数字以外じゃダメだからね!」と言っても遅い。
もし、悪いやつが「";DELETE FROM geekDB;」なんて入力したら、なんとデータが消えてしまうΣ(゚Д゚)
あぶねぇぇぇえええ!あな、おそろしや・・・おそろしや・・・。
紅が無知なだけというせいもあるけど、世の中には、思いもよらぬ行動を取る人がいるんだなぁと痛感。
だって!URL欄にクエリ打ち込むて!!うちの母親なんてアドレスバー非表示にしてるつうの!!


話がそれた。まとめよう。今回覚えたこと。

「$idは数字以外は受け付けない」というのは、クエリ実行後ではなく、
一番最初に言わなければいけない。



それでは、追加したコードを移動。

3    mysql_connect('localhost','ユーザ名','パスワード');
4    mysql_select_db('データベース名');
5    mysql_query("set names utf-8");
6
7  //id=数字以外はエラーメッセージを表示
8   if(!is_numeric($id)){
9   echo "該当データがありません";
10  }
11   else{
12  //ここまで
13   
14    $sql="select * from geekDB where id = " . $id;
15    $result = mysql_query($sql);
16
17   while ($item = mysql_fetch_array($result)) {
18   ・・・(以下略)



これでOK、今度こそOK。
テーブルは消えないわ、私が守るもの!


LINEで送る

GETメソッドでデータを受け取る

  • 2008/06/23(月) 23:00:00

更新情報

竹迫さん、phaさん、ひろゆきさん、いとまささんを追加しました!ありがとうございます!!
日本のGeeksは本当に優しい。泣けてくるぜよ><
geek DataBase - ギークデータベース


$_GETの値をキーに、データベースからデータを読み取る

以下、個別ページのPHPソース
※解説は 『MySQL入門以前』 を参考に書いています。


1 <?php
2   extract($_GET);
3    mysql_connect('localhost','ユーザ名','パスワード');
4    mysql_select_db('データベース名');
5    mysql_query("set names utf-8");
6
7   $sql="select * from geekDB where id = " . $id;
8   $result = mysql_query($sql);
9
10 // id=数字以外はエラーメッセージを表示
11    if(!is_numeric($id)){
12     echo "該当データがありません";
13     }
14     else{
15 // ここまで
16
17     while ($item = mysql_fetch_array($result)) {
18     echo "<h2>";
19     echo $item["name"];
20     echo "</h2>";
21 ・・・(中略)・・・
22      }
23     }
24 ?>



2行目はGETメソッドで送られてきたデータの受け取りを許す、という意味。


3〜5行目はお決まりの手順。データベース接続&文字コード指定。


7,8行目もPHPを使ってMySQLを操るとほぼ同じなんだけど、
今回は where id = " . $id というのがくっついてる。何が違うか。
ある条件に適合するデータだけを表示したい場合は、select文の末尾で条件を指定するそうな。
つまり、$id のデータだけを表示させたいと。


11〜14行目は、実は最初にUPしたときは入れてなかった。
公開後にTwitterやメール等で何人かにご指摘いただき、慌てて追加><
これがないとどうなるかというと・・・

たとえば、アドレスバーのURLに”id=A ”や”id=あ”といった数字じゃない文字を入力すると、
真っ白な画面になってしまう。なぜって、そんなデータはないから。
idのデータ型はINT。数字しか使えない。

これを回避するために、idが数字以外だったらエラーメッセージを出すことに。
試行錯誤の末、ようやく変数が数字かどうかを調べる関数を発見!

is_numeric 変数が数値か調べる

is_numeric(変数名)
戻り値:数値の場合はTRUE,数値ではない場合はFALSE

参考:『PHP辞典 第2版 (DESKTOP REFERENCE)


if〜else構文を使って「もし $id が数字じゃなかったら {中カッコ} 内の処理を実行せよ。それ以外(つまり$idが数字)だったら else 以下を実行せよ」と命令したい。
真/偽を反転させるには””を使う、と以前ナイスギークに教わった。
参考:6日目 クッキー受け取ってください!

だから、is_numeric の頭に””を付ければOK!(←これは感情を込めたエクスクラメーションマーク)


17行目もと同じ。
18行目以下はひたすら echo が続くだけなので省略。
22,23行目で {中カッコ} を閉じて終了♪



やーやー。めでたしめでたし。
このページを作れば、あとはDBにどんどんデータを追加していくだけでいいのだよ!素晴らしい!!
ビバDB!データベースばんざい\(^o^)/ ドラゴンボールばんざい\(^o^)/


LINEで送る

GETメソッドでデータを送る

  • 2008/06/19(木) 00:00:00

日記

 はてなアイドルをコンパイルしてきた。リアルで。楽しすぎてやばかった><


$_GETを使ってプロフィールページにidデータを渡す

geek DataBase - index.php PHP部分のコードだけ貼るね!


1 <?php
2   mysql_connect('localhost','ユーザ名','パスワード');
3   mysql_select_db('データベース名');
4   mysql_query("set names utf8");
5
6   $sql="select * from geekDB";
7   $result=mysql_query($sql);
8   $rows=mysql_num_rows($result);
9
10  while ($item = mysql_fetch_array($result)) {
11
12   echo "・";
13   echo " ";
14   echo "<a href="http://geekdb.jp/geek.php?id=";
15   echo $item['id'];
16   echo "">";
17   echo $item['name'];
18   echo "</a><br />";
19   }
20 ?>



2,3行目は以前と同様。MySQLに接続→データベースを指定。
PHPを使ってMySQLを操る


4行目。
文字コードをセットするクエリを送信。最初、文字化けしまくりングで激怒していた。





で、この1行を入れれば解決か?というと、そうでもない。まだ化ける。なぜだ。

<meta http-equiv="Content-Type" content=="text/html; charset=Shift_JIS"/>


実はヘッダで charset=Shift_JIS と指定してしまっていたのね。

htmlちゃん 「文字コードは Shift_JIS で出力ですね!」
MySQLくん 「否!文字コードは utf8 と指示されたぞ!」

という具合に、2人(?)がケンカをしてしまった(´・ω・`)
けんかをやめて!2人を止めて!私のために争わないで・・・!

解決策つ charset=utf8

同一ファイル内の文字コードは統一しなくちゃ。htmlの文字コードをutf8に直して、いっちょあがり!


6,7,8行目も、PHPを使ってMySQLを操るの時と一緒。


10行目から始まる while 文も、構造的には前回と同じなんだけど、ポイントは14〜16行目。
マークは”エスケープ文字”といって、ダブルクォーテーションの中でダブルクォーテーションを使う場合は、その直前にを入れてエスケープしなきゃいけないらしい。パッと見、ややこしいよね(`・3・)
PHPを考えずに、htmlタグだけで書いてみよう。

<a href="http://geekdb.jp/geek.php?id=$item['id']">


ギークさんの個別ページへのリンクタグ。
個別ページは1人1人別々に作るのではなく、geek.phpという1ページだけ。
このページは、名前など各項目のフォーマットを用意した単なる受け皿。
肝心のデータは、データベースから引っ張ってくる。
その引っ張る際に必要となるキーが、$item['id']。ギークさんの id を手がかりに、データを呼び出す。
$_GET を使ってるんだけど、$_GET の話はむかぁーしチラっと書いたような・・・
1日目 見つけて 私のセキュリティホール

あれ、ちゃんとアウトプットしてなかった。ごめん><;;

GETメソッドによるデータの送り込み方
URLの後ろに「?変数名=値」を追記することで、その変数名と値を「URL」に送り込むことができます。
複数の変数を送り込みたい場合は「?変数名=値&変数名=値」のように書きます。

参考:MySQL入門以前

今回のケースで言うと、http://geekdb.jp/geek.php というURLの後ろに ?id=$item['id'] と追記することで、変数 id とその値(ギークさんのid)をgeek.phpに送り込んでいる。


これ、表示されたときはマジで感動した!「ハッ!」ってリアルで言った。一瞬、呼吸止まった。
私が書いたコードが、私のデータベースからデータを呼び出してくれた!ブラウザに表示してくれた!!
ミラクルガールすぎる・・・・!!プログラミング超たのしいいいいいいいい!!!!!

LINEで送る

geekDBきたああぁぁぁああ!!!

  • 2008/06/16(月) 20:30:00

ちょっと!アンタ!!!!!!!
見てよこのサイト!プログラムで動いているよ!!拡張子が.php!すごいぞ!すごいぞ!!!


geek DataBase - ギークデータベース


掲載を許可してくださったギークの皆様、この場を借りて心からお礼申し上げます。

まだデザイン全然考えてなくてひどいサイトだけど、ご容赦ください><
今後どんどんブラッシュアップしてアップデートしてコンパイルして、
日本一のデータベースにするど(`・ω・´)
追加したい情報や実装したい機能(←この言い回しカコイイ)がたくさんあるのだ!
わぁーーーい!オラ、わくわくしてきたぞーーーー!!!


各ページのソースは、別エントリでうpするにょ。嬉しかったので取り急ぎご報告まで。
プログラミングってたのしい!

LINEで送る

デバッグのコツ

  • 2008/06/16(月) 13:30:00

バグを見つける方法

大事なことなので未来の自分のためにメモ。


Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource

というエラーばかり出てイラっちょしてたけど、こういう場合、print_r を使って変数に何が入っているかを見ると良い。var_dump でも可。

エラーを出してしまうこと自体は問題ではない。
それをどうデバッグするかが大事なのだ!!


あるいは、コードを一番シンプルなものに書き換えて試してみる。
極力、不要なものを取り除いて、エラーを引き起こしてる犯人を追いつめるのだ!!


かのあきやん大先生は、エラーが出ると
「その変数に何が入ってる?print_rしてみて!」とアドバイスするそうな。(友人談)

けんすう先生は、
echo "<pre>";
print_r $hoge;
echo "</pre>";

を辞書登録してるとか。ふむむ。print_r 大事だな。

  

あいつマジすごいな!勉強になった!

LINEで送る