SQLインジェクション対策とは?シングルクオーテーションとダブルクオーテーションの違い

このQ&Aのポイント
  • SQLインジェクション対策として、シングルクオーテーションが重要ですが、ダブルクオーテーションはエスケープする必要はありません。
  • SQLite3::escapeStringを使用して値をエスケープすれば、シングルクオーテーションが追加されますが、ダブルクオーテーションは追加されません。
  • したがって、ダブルクオーテーションはエスケープせずに使用しても問題ありません。
回答を見る
  • ベストアンサー

SQLインジェクション対策(クオーテーション関連

PHP Version 5.4.7の環境にて。 SQLite3::escapeStringを使って、 SQLインジェクション対策をしようと考えています。 HTMLの<form>からPOSTで値を受け取り、 その値をSQL文に入れ込み、 そのクエリ(※ちなみに、INSERTのみです。)をSQLite3のDBに対して行う、 なんてことをする際の、 SQLインジェクション対策として、お考え下さい。 POSTで受け取る値に入っていたら危険なものとして、 「シングルクオーテーション」が、まず、挙げられるかと思います。 「'」 ←これです。 さて、「"」 ←こちらはダブルクオーテーションですが、 こちらのダブルの方はエスケープする必要は無いのでしょうか? (例)※wikipediaより SELECT * FROM users WHERE name = '(入力値)'; SELECT * FROM users WHERE name = 't' OR 't' = 't'; → このSQL文では条件が常に真となるため、 nameカラムの値にかかわらず、全レコードが選択される。 → ということで、入力値に、 エスケープされていない「シングルクオーテーション」をそのまま使うのはNG。 ここまではOKです。 では、次に、ダブルクオーテーション版で、 SELECT * FROM users WHERE name = "(入力値)"; SELECT * FROM users WHERE name = "t" OR "t" = "t"; こちらはどうなのでしょうか? (シングルをダブルに変えただけですが。) ---------- ちなみに、 SQLite3::escapeString にて、 (1) $var = "Let's"; //←シングルクオーテーション $db = new SQLite3(':memory:'); $escaped_var = $db->escapeString($var); echo $escaped_var; //Let''s と表示される (「 ' 」が1つ追加される。) (2) $var = 'Let"s'; //←ダブルクオーテーション $db = new SQLite3(':memory:'); $escaped_var = $db->escapeString($var); echo $escaped_var; //Let"s と表示される (何も追加されず。) というように、 シングルクオーテーションはエスケープされるが、 ダブルクオーテーションの方ではエスケープされませんでした。 これは、つまり、 ダブルクオーテーションの方は危険視されていない、 ということだと思いますが、 でも、本当にダブルクオーテーションをエスケープせずに、 そのまま、SQL文につっこんでも大丈夫なのでしょうか?

  • march4
  • お礼率83% (628/754)
  • PHP
  • 回答数5
  • ありがとう数5

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

  • ベストアンサー
  • shimix
  • ベストアンサー率54% (865/1590)
回答No.2

SQL文の中で「文字列」を単引用符で括っているなら、その中にある二重引用符は「単なる文字」としてしか認識されません。なのでエスケープする必要はありません。逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。 「適切なエスケープをする」というのは、そういうことです。 結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいいということになります。

march4
質問者

お礼

回答をありがとうございます。 >逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。 ですよね! つまり、 $sql = 'SELECT * FROM users WHERE name = "(入力値)"'; というようにコーディングをしている場合には、 「二重引用符のエスケープは必須」ということですよね。 >結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいい なるほど。そういう考え方があるわけですね。 ちなみに、その『プレースホルダを使う場合』においては、 エスケープ処理は、どのように、なされているのでしょうか? システムが、渡されてきた文字列を見ながら、適宜、 SQL文内における「文字列を括る引用符」を、 適切にチョイスしてくれる、ということでしょうか。 (つまり、人間が手動でエスケープ処理をしなくてよく、 すべて、システムにお任せできてしまう?) 「'」だろうが、「"」だろうが、 また、「バイナリセーフじゃない文字列」だろうが、 そのまま、システムに丸投げできてしまう、 ということでしょうか。 ※「バイナリセーフじゃない文字」までは、 さすがに丸投げはできないかもしれませんが・・・。 (さらに、色々と聞いてしまい、すみません。) もし、宜しければ、教えて下さい。

その他の回答 (4)

  • shimix
  • ベストアンサー率54% (865/1590)
回答No.5

#あ、先に書かれた(汗 thx.>agunuzさん 少なくともプリペアドステートメントが使える関数・クラスを利用しているのであれば「内容の保証がない」データはプリペアドステートメントで扱うべきですね。そうすれば括るのが単引用符か二重引用符かなんて気にする必要はありません(気にしなくても適切に処理されます)。もちろんバイナリデータでも。です。

march4
質問者

お礼

何度もありがとうございます。 適切にプリペアドステートメントを使っていれば、 どんな文字列を打ち込まれようとも大丈夫だい! という風に解釈いたしました。

  • agunuz
  • ベストアンサー率65% (288/438)
回答No.4

>「そのまま」ということは、適切にエスケープすることなく、 >という意味でしょうか。 > >つまり、マズイ という意味? あ、いえ「普通の文字列と同じように」扱えるということです。たとえばphpスクリプトでは、文字列型の変数の内容がテキスト(asiiなのか日本語なのかも不問)であってもバイナリであっても同じように扱ってかまいません。 当然ですが『適切にエスケープする』ことが前提です。

march4
質問者

お礼

回答をありがとうございます。 バイナリの件ですが、 「'」を含まない文字列の中で、 もし、下記の「入力値」の所に入れられてしまうと、 SELECT * FROM users WHERE name = '(入力値)'; SQLインジェクションが成立してしまうような、 そんな文字列はありますでしょうか? あるなら、バイナリ文字でしょうか?! もし、そうであるなら、 そのバイナリ文字さん達は、どうやってエスケープすればいいんだ?! 以上が、私が質問したかったことになります。 またよろしければ、教えてください。(ぺこり

  • shimix
  • ベストアンサー率54% (865/1590)
回答No.3

>ちなみに、その『プレースホルダを使う場合』においては、 >エスケープ処理は、どのように、なされているのでしょうか? 基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることになります(各DBのドライバで微妙に違う部分もあります)。 何故データベースによって違いがあるかといえば、それはエスケープした結果を各データベースがどう扱うかが異なるからです。不要な部分までエスケープした結果、正しく格納できなくなったら困りますので。mysql_real_escape_stringなどは両方ともエスケープしますが、これはその状態で渡された文字列をMySQLがキチンと戻して格納するからです。 http://www.php.net/manual/ja/function.mysql-real-escape-string.php データベース関係のエスケープ処理の多くは「文字列型は単引用符で括る」ことを前提に書かれています。SQLite3のescapeに関する下記のノートなどを読むと一目瞭然でしょう。 http://www.php.net/manual/ja/sqlite3.escapestring.php またBlobなどのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。

march4
質問者

お礼

回答をありがとうございます。 また理解が深まりました。 >基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることに >データベース関係のエスケープ処理の多くは「文字列型は単引用符で括る」ことを前提に書かれています。 ということは、SQL文で文字列型を扱う際には、慣例に従い、 「単引用符で括る」ようにしておいた方が良い、ということになりますね。 これを、二重引用符で括るようなコーディングを続けていると、 ↓ 「SQL文の文字列型を二重引用符で括る」 かつ 「悪意ある二重引用符を含む値をユーザから受け取る」 ↓ その結果、 プリペアドステートメントを使っていても、 もともと、二重引用符にはエスケープはされないため、 最悪の場合、SQLインジェクションが成立してしまう、 ということになりますものね。 >SQLite3のescapeに関する下記のノートなどを読むと一目瞭然 二重引用符はエスケープされないから気をつけろ! (二重引用符をエスケープしない仕様になっている理由などもゴニョゴニョ。) みたいなことが英語で書かれていましたね。 本件と非常に関わりの深いノートでした。 >またBlobなどのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。 すみません(汗) ここの意味が、能力の低い私にはよく分かりませんでした。 >バイナリデータもそのまま扱います 「そのまま」ということは、適切にエスケープすることなく、 という意味でしょうか。 つまり、マズイ という意味? >これが出来ないデータベース 「これ」とは、何でしょう。 バイナリデータをそのまま扱うこと。 ? それとも、 バイナリデータをそのまま扱わず、エスケープしてから扱うこと。 ? それとも、 また別のことでしょうか。 >これが出来ないデータベースの方が少数派 出来ない方が、マズイ という言い方なのですよね、きっと。 (そんなマズイDBの方が少数派ですよ、という風に理解しました。) もし、またよろしければ、教えて下さい。

回答No.1

SELECT * FROM users WHERE name = "(入力値)"; DBによっても違うかもしれないけど、そもそも上記SQLは通るの? http://www.dbonline.jp/sqlite/type/index4.html

march4
質問者

お礼

回答をありがとうございます。 >そもそも上記SQLは通るの? ここで話題にしている「SQLite3のDB」では、 SQL文の中で文字列をダブルクオーテーションで、 くくることは出来るようです。 参考: http://programing.dip.jp/index.php?SQLite%2F%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E6%93%8D%E4%BD%9C

関連するQ&A

  • 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
  • ASPでのSQLインジェクション対策

    ASPにて、ADOでAccessにアクセスする際にSQLインジェクション対策はどのようにしたらよいでしょうか。 現状は以下の様にしています。(name)は画面から受け取ったパラメータです。 Set aConn = CreateObject("ADODB.Connection") aConn.Provider = "Microsoft.Jet.OLEDB.4.0" aConn.ConnectionString = Server.MapPath("DB.mdb") aConn.open SQL = "SELECT A FROM TBL WHERE NAME = " & name ...... 宜しくお願いします

  • '(シングルクォーテーション)の検索

    '(シングルクォーテーション)の検索 SQL Server 2005 Express Edition を使っています。 '(シングルクォーテーション)を含む文字列を検索したいのですが できずに困っています。 どのようなクエリを組むべきでしょうか? 教えてください。 よろしくお願いします。 現在は select * from テーブル名 where 列名 like '%\'%' としていますがエラーになります。

  • ダブルコーテーションやシングルコーテーション

    私の持っている参考書の中に、次のように、 変数をダブルコーテーション、シングルコーテーション、およびピリオドで囲んでいるSQL文があるのですが、 この場合、なぜ、ダブルコーテーション、またはシングルコーテーションのみでは駄目なのでしょうか? [参考書の記載] where カラム名>="'.変数.'" ※変数は日付が入ります。varchar型です。

    • ベストアンサー
    • MySQL
  • PHPでjavascriptを書き出すときのクォーテーションの使い方

    PHPで書き出したSQL文をjavascriptの関数に渡すなどしていて、 ダブルクォーテーションやシングルクォーテーションが4つ以上の入れ子になったときどのように表現すればよいのでしょうか? 例 $a = "<a onClick=\"test('SELECT * FROM table WHERE field = 'field'')\">text</a>"; *test()はjavascriptの関数とします。 このように入れ子が深くなっていったときの回避の方法やクォーテーションの使い方の規則などあれば教えてください。

    • ベストアンサー
    • PHP
  • SQLインジェクションが発生する理由

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

  • SQLインジェクション

    教えてください。 よろしくお願いいたします。 SELECT * FROM table WHERE user='$uid' AND password='$pass' のエスケープ処理をしていない場合に、 ID=aaa パスワード='or'a'='a と入力されると、 SELECT * FROM table WHERE user='aaa' AND password="or 'a'='a' が実行されてしまいますが、 「password=」と「or」の間のダブルクォーティションは、 どのような意味を持つのでしょうか。

  • SQLiteのLike句で抽出できない

    SQLiteのLike句で抽出できないレコードがあります。 原因についてご教授いただけますでしょうか。 以下、操作手順になります。 ■データベースの作成 C:\>sqlite3.exe member.db SQLite version 3.7.15.2 2013-01-09 11:53:05 Enter ".help" for instructions Enter SQL statements terminated with a ";" ■テーブルの作成、レコードの追加 sqlite> create table t_member(name text, age integer); sqlite> insert into t_member values('山田一郎', 25); sqlite> insert into t_member values('田中次郎', 35); sqlite> insert into t_member values('鈴木三郎', 45); ■検索 sqlite> select * from t_member where name like '%一郎'; 山田一郎|25 sqlite> select * from t_member where name like '%次郎'; 田中次郎|35 sqlite> select * from t_member where name like '%三郎'; sqlite> 三郎だけが検索条件に適合しないのは何故でしょうか。 よろしくお願いします。

  • シングルクォーテーションとダブルクォーテーション

    いつも楽しく拝見させて頂いています。 初心者ですが宜しくお願いします。 シングルクォーテーションとダブルクォーテーションの使用方法について質問させて頂きます。 select文でテーブル名を指定するときはそのまま(たとえば'名前'じゃなく名前)しないとエラーになります。そういう風なシングルクォーテーション(又はダブルクォーテーション)を使ってはいけないところ、またシングルクォーテーションにしないといけないところ、ダブルクォーテーションにしないといけないところを教えて頂けますでしょうか?もし両方OKならその違い等も教えていただけるとうれしいです。 以上宜しくお願いします。

    • ベストアンサー
    • MySQL
  • Oracleのシングルクォーテーション

    いつもお世話になっております。 Oracleの「'(シングルクォーテーション)」の使い方について教えてください。 テーブルAのフィールド001には2桁の数値が文字列型として格納されています。 (1)SELECT COUNT(*) FROM テーブルA WHERE フィールド001 = '09' でデータの抽出をしているのですが、データがあるにも係らず、「0」となってしまいます。 (2)SELECT COUNT(*) FROM テーブルA WHERE フィールド001 = 09 では、「09」だけでなく「9」までカウントしてしまいます。 データの中には「09」「9」が混在していて、これらを別々にカウントしたいのですが、(1)では結果を得ることが出来ません。シングルクォーテーションの使い方に間違いがあるのでしょうか? 別々にカウントする方法があればご教授いただけないでしょうか? よろしくお願いします。

専門家に質問してみよう