SQL実習サイトでのSQLインジェクション対策について

このQ&Aのポイント
  • HTML+CSS+PHP+MySQLで作成している「SQL実習サイト」では、フォームから直接SQL文を入力して実行できるようにしています。その際、SQLインジェクション対策について検討しています。
  • IPAの「安全なSQLの呼び出し方」では、プレースホルダ(プリペアド・ステートメント)を使用することが有効とされています。しかし、直接SQLを実行するため、プレースホルダは使用できない可能性があります。
  • 「SQL実習サイト」では、SELECT文のみ実行できるようにすることを考えています。ユーザが入力したSQL文の中で「SELECT」を検出して、自作のSQLインジェクション対策を行うことを検討しています。ただし、DELETEやUPDATEなどの文がある場合は無効化する必要があります。このような使い方では、SQLインジェクション対策は可能でしょうか?
回答を見る
  • ベストアンサー

SQLを直接フォームから入力するプログラムについて

HTML+CSS+PHP+MySQLで「SQL実習サイト」を作っています。 SQLを入力し、その結果を確認するという学習用のサイトです。 現在はXAMPP上で動かしているだけですが、上手くできたらWeb上に上げる予定です。 質問は、そのサイトでのSQLインジェクション対策についてです。 作成している「SQL実習サイト」では、フォームにSQL文を直接入力してもらい、そのままその SQL文をPHPで実行するようにしています。 具体的には、POSTで自分自身(index.php)にSQLを送信し、それをクエリとして実行しています。 <h2>SQL入力</h2> <form action="index.php" method="post">     <textarea name="input_sql" cols=38 rows=3></textarea>     <input id="sql" type="submit" value="SQL実行"> </form> (~略~) $_SESSION['jikkou_sql'] = $_POST['input_sql']; (~略~) $sql = $_SESSION['jikkou_sql']; $query = mysql_query($sql, $conn); IPAの「安全なSQLの呼び出し方」等から調べると、SQLインジェクション対策としては プレースホルダ(プリペアド・ステートメント)が有効だとありますが、 作成しているケースだとSQLを直接実行するのでプレースホルダが使えない気がします。 「SQL実習サイト」ではSELECT文のみ実行できるようにしたいと考えています。 入力してもらったSQLの中で「SELECT」を探すようにして自作のSQLインジェクション対策を 行えばよろしいのでしょうか?(DELETEやUPDATEがあれば無効化したり・・・) それとも、そもそもこのような使い方ではSQLインジェクション対策はできないのでしょうか? ご教授よろしくお願いします。

  • PHP
  • 回答数4
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
noname#244856
noname#244856
回答No.2

サブクエリなどもあるので、先頭がSELECTかどうかだけを判定するだけではさすがに不十分すぎます。オススメの方法としては、MySQLを捨ててSQLiteを使うことです。SQLiteであればユーザーごとにファイルを生成することができ、個別のデータベース空間を与えることが出来ます。この状態であれば何されても特に問題はありません。(重いSQL実行によるサーバー負荷とかは注意) PHPでデータベースに接続するときのまとめ http://qiita.com/mpyw/items/b00b72c5c95aac573b71 ・mysql_query関数は問答無用でやめましょう… ・ユーザーが実行不能なSQLを投げてくることも想定し、「PDO::ERRMODE_EXCEPTION」を有効にしておき、例外を捕まえられるようにしましょう。

sou-dan
質問者

お礼

回答ありがとうございます。 古い書籍を参考にしているので現状ではmysql関数でした… 実際に上げるときはPDOにしようと思います。 また、想定しているレンタルサーバがMySQLのみ対応です。 まだレンタルしていませんのでSQLiteも視野に入れて考えてみようと思います。 SQLiteでユーザーごとにファイルを生成する、ということに対しての理解は 私自身は不十分ですので調べてみます。ありがとうございます。

その他の回答 (3)

noname#244856
noname#244856
回答No.4

>> また、想定しているレンタルサーバがMySQLのみ対応です。 SQLiteってただの "1つの" ファイルだけでデータベースのように扱えるものなんですよね。レンタルサーバーがもし「MySQLしか対応していない」という表記でも、SQLiteは使えるというケースがあります。レンタル前にサーバー管理者に「PDO_SQLITEは使えますか?」と聞いてみるのもいいと思います。

sou-dan
質問者

お礼

回答ありがとうございます。 SQLiteを使う方向で考えて見ます。 また、No5さんが回答してくださったように想定しているレンタルサーバでも SQLiteは使えるようです。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.3

所詮プレースホルダは「値を安全に渡せる」というだけのことですから SQLをそのまま走らせるような処理は無理ですね ただ考えてみれば、インジェクション対策の意義は (1)データ挿入・更新・削除など勝手にされないようにする (2)アクセスできるdbやtableを制限する (2)表示させるカラムやレコードを制限する という趣旨ですから、実行ユーザーの権限をうまく抑制すれば理論上問題は 極小化できます。むしろ、とかく手抜きでDSNにrootユーザーを設定しがちですが、 検索だけが目的なら本来どんなSQLの発行も権限を抑えられたユーザーにすべきです。 あとはたぶん汚いSQLが大量に流れてくるでしょうから、エラー処理など適切に 設定する必要はあるでしょう。

sou-dan
質問者

お礼

回答ありがとうございます。 PHPで対策をすることしか考えていませんでしたので、DBの権限のことは どのように実現できるかわかりませんので調べてみます。 また、エラー処理は現状では、 if(!$query) → エラーメッセージ と、クエリがおかしい場合のみのエラーメッセージ表示のみです。

回答No.1

DBの接続ユーザーを新規に作成して、特権情報でselectのみを許可する。 root権限のない、レンタルサーバーじゃ無理だろうけど…。

sou-dan
質問者

お礼

回答ありがとうございます。 想定しているレンタルサーバはさくらインターネットです。 調べたところroot権限があるような感じはしなかったです…。 もう少し調べてみます。

関連するQ&A

  • prepareでSQLインジェクション対策?

    PHPでMySQLを操作しています。 PDOのprepare()を使えば(プレースホルダを使えば?)、SQLインジェクションは必ず発生しないと言えますか? もし、そうだとすれば、SQLインジェクション対策はかなり簡単ですよね?でも、セキュリティの話でよく取り上げられるということは、実際は他の問題が発生したりするんですかね?

    • ベストアンサー
    • PHP
  • SQLインジェクションについて

    SQLインジェクション対策についてご質問があります。 SQLを入力してそのまま実行するプログラムを作ろうとしています。 ユーザーが入力したSQLをプログラム側でSQLインジェクションを含むかどうかの判定が できるようにしたいのですが、可能なのでしょうか? よろしくお願い致します。

  • XSS、CSRF、SQLインジェクションについて

    XSS、CSRF、SQLインジェクションをそれぞれ簡単に説明すると、 XSS・・・動的なWebサイトにおける入力フォームの脆弱性 CSRF・・・ユーザーになりすましてWebサーバーにリクエストすること SQLインジェクション・・・アプリケーションが実行するSQL文に変なものを注入して、意図しない 動作をさせる攻撃のこと で正しいですか?

  • SQLインジェクションの対策

    SQLインジェクションの対策 いつもお世話になっております。 SQLインジェクションの対策についてお伺いいたします。 もともと↓のようなSQL文だったものを "select user_id from table where user_id='{$user_id}'" 以下のように変更しました。 "select user_id from table where user_id='" . mysql_real_escape_string($user_id) . "'" 以下のように実行されていたSQL文は select user_idfrom table where user_id='10001' and 'a'='a' ↓のようにエスケープ処理して実行されるようになりました。(入力値は「10001' and 'a'='a」) select user_id from table where user_id='10001\' and \'a\'=\'a' ですが、phpMyAdminで実行してみるとどちらのSQL文も同じ結果が取得できてしまいます。 これでは対策になっていないと思ったので、質問させていただきました。 (magic_quotes_gpcはoffに設定しています。) なにか他の方法がいいのでしょうか。 ご教示よろしくお願いいたします。 <環境> PHP 5.1.6 MySQL 5.0.45

    • ベストアンサー
    • PHP
  • 入力フォーム内容のDB保存について

    MySQLへの登録処理についての質問お願いします。 サイトの登録用ページを作っていていて、PHPでmySQLにデータを保存する。 というながれのプログラムを作っています。 空白のまま「送信」を押すと、空白エラー「メールアドレスを入力してください」のメッセージが出るようになっています。 その後のDB保存がどうしてもうまくいかないので間違えをご指摘いただければ幸いです。 DB接続は、 'データベースに接続しました'と表示されています。 soushin.phpの最後に記述しているheader('Location: soushin.php');が正しいのかもわかりません。 よろししくお願いします。 //index.php <html> <body> <form action="" method="POST" > <label for="mail">メールアドレス</label> <input name="mail" type="text" id="mail" size="35" maxlength="255" > <?php if($error['mail'] == 'blank'):?> <p class="error">メールアドレスを入力してください</p> <?php endif; ?> <br> <input type="submit" value="上記に同意して仮登録メールを送信"> </form> </body> </html> //soushin.php <?php session_start(); mysql_connect('localhost','my_db','') or die(mysql_error()); echo 'データベースに接続しました'; mysql_select_db('kaiin_touroku'); mysql_query('SET NAMES UTF8'); if (!isset($_SESSION['join'])) {     header('Location: index.php'); exit(); } if (!empty($_POST)){     //登録を処理する     $sql = sprintf('INSERT INTO kaiin_touroku SET mail="%s"',     mysql_real_escape_string($_SESSION['join']['mail']) ); mysql_query($sql) or die(mysql_error()); header('Location: soushin.php'); } ?> <!DOCTYPE HTML> ・ ・ ・ <form action="" method="post">  <dl>  <dd> <?php echo htmlspecialchars($_SESSION['join']['mail'], ENT_QUOTES, 'UTF-8'); ?>に送信いたしました。  </dd>  </dl>  </form>

    • 締切済み
    • PHP
  • SQLインジェクションが発生する理由

    初めての質問です。よろしくお願いします。 今現在、SQLインジェクションというものが問題になっていますよね いろいろなサイトを回って調べて見たのですが、具体的な対策として、「'(シングルクォーテーション)」などの特殊文字を確実にエスケープすること、くらいしか対策が書かれておりません。 特殊文字のエスケープさえしっかりしておけばSQLインジェクションは発生しない、という印象を受けたのですが、SQLインジェクションがおきてしまったサイトではエスケープ処理をしていなかったということなのでしょうか? それとも、エスケープ処理をしていても何らかの方法で不正なSQLの命令を実行されてしまうのでしょうか? どうにもわからなくて困っているので、どうかよろしくお願いいたします。

  • SQLファイルの読み込み

    PHP上にSQL文を書くことはできますがSQLファイルを読み込むことはできるのでしょうか? 例えばSQL上では %\i create.sql のように実行してテーブルを作りますがこれを同じようにPHP上で $conn = pg_connect("host=localhost dbname=**** user=****"); $query = "\i create.sql"; pg_query($conn, $query); と記述してもエラーになってしまいます。 PHP上ではそもそも読み込みはできないのでしょうか? それとも文字型の指定などが間違っているのでしょうか?

    • 締切済み
    • PHP
  • フォームの入力途中でのプレビューについて

    フォームの入力途中でのプレビューについて質問させてください。 以下のようなフォームがあります。 <form action="sample.php" method="post"> <textarea rows="2" cols="50" name="aaa"></textarea> <input type="submit" value="プレビューする"> <textarea rows="2" cols="50" name="bbb"></textarea> <input type="submit" value="送る"> </form> このフォームの途中の「プレビューする」を押すとそれ以前の入力項目の内容である"aaa"をsample.phpではなく別のphpに送ってプレビューしたいと思っています。 最後の"送る"ボタンを押すとすべての内容がsample.phpに送られます。 このようにフォームの途中でformのaction属性に指定したところとは別のphpに値を送ってプレビューするようなことは可能でしょうか? 解決方法を御存知の方がいらっしゃいましたらよろしくお願いします。 また、他の方法によってフォームの記入内容の途中までをプレビューする”ことが実現可能であるようであればその方法も教えていただけると幸いです。よろしくお願いいたします。

    • 締切済み
    • PHP
  • SQLインジェクション及びクロスサイトスクリプティング対策について

    MYSQLとPHPの掲示板があったのでどちらで質問させて頂こうか悩んだのですが、こちらの方に書き込みさせて頂きます。 現在、PHPとMYSQLを用いたプログラミングの勉強をしています。 そこで一つ疑問に感じた事がありましたので、お尋ねしたく投稿させて頂きます。 PEARなどを使わずに、平でSQL文を発行して表示しているのですが… SQLインジェクション対策・クロスサイトスクリプティング対策として以下の4つに気を付けています。 1. 文字コードはUTF8を使用 2. マジッククォートは基本的にオフ。オンの場合はスクリプト中でstripslashesを実行 3. 2のマジッククォート対策のあとにデータのインサート時に全ての挿入文字列にmysql_real_escape_stringを実行 4. データの出力時にhtmlspecialcharsを実行 以上の対策でSQLインジェクション対策及びクロスサイトスクリプティングについては十分でしょうか? コードも出さずに漠然とした質問なので返答しづらいかもしれませんが、幅広くご意見を頂けましたら助かります。 よろしくお願いします。 ※幅広くご意見頂きたいと思っておりますので記事の終了やお礼が遅くなってしまったらすみませんm(_ _)m

    • ベストアンサー
    • PHP
  • SQLインジェクションの危険性について[MYSQL]

    下記のコードはPHPプログラマ一年生の自分から見ても、 POST入力値をチェックしていない危険なコード(一部を抜粋)だと 思うのですが先輩は問題ないと言い、修正する気がありません。 そこで、SQLインジェクションのようなSQL文を送信された場合に ユーザー名とパスワードが表示されれば納得すると思い いろいろテストしてみたのですが、うまく表示されません。 実はSQLインジェクションなどの問題ないソースなのでしょうか? ご教授、よろしくお願いいたします。 ■テーブル構成(ユーザ・パスワード管理テーブル) CREATE TABLE `sample`.`test` ( `user_id` INT NOT NULL , `passwd` VARCHAR( 32 ) NOT NULL ) ■問題の処理分 <?php $user_val = "" ; $pass_val = "" ; if (isset($_POST["user_id"]) == TRUE) {   $mysql_c = mysql_pconnect('******' , "******" , "******");   mysql_select_db("******" , $mysql_c);   $sql = 'select * from test where user_id = ' . $_POST["user_id"] ;   $result = mysql_query($sql , $mysql_c);   if ( $result != false)   {     if(($row = mysql_fetch_object($result)) != false )     {       // パスワードチェック       if ( $row->passwd != $_POST["pass"] )       {         echo "check NG" ;       }       else       {         $user_val = $row->user_id ;         $pass_val = $row->passwd ;       }     }   } } ?> <FORM action="index.php" method="post" > <input type="text" name="user_id" value="<?php echo $user_val ?>" > <input type="text" name="pass" value="<?php echo $pass_val ?>" > <input type="submit"> </FORM>

    • ベストアンサー
    • MySQL