- ベストアンサー
SQLインジェクション対策とは?シングルクオーテーションとダブルクオーテーションの違い
- SQLインジェクション対策として、シングルクオーテーションが重要ですが、ダブルクオーテーションはエスケープする必要はありません。
- SQLite3::escapeStringを使用して値をエスケープすれば、シングルクオーテーションが追加されますが、ダブルクオーテーションは追加されません。
- したがって、ダブルクオーテーションはエスケープせずに使用しても問題ありません。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
SQL文の中で「文字列」を単引用符で括っているなら、その中にある二重引用符は「単なる文字」としてしか認識されません。なのでエスケープする必要はありません。逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。 「適切なエスケープをする」というのは、そういうことです。 結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいいということになります。
その他の回答 (4)
- shimix
- ベストアンサー率54% (865/1590)
#あ、先に書かれた(汗 thx.>agunuzさん 少なくともプリペアドステートメントが使える関数・クラスを利用しているのであれば「内容の保証がない」データはプリペアドステートメントで扱うべきですね。そうすれば括るのが単引用符か二重引用符かなんて気にする必要はありません(気にしなくても適切に処理されます)。もちろんバイナリデータでも。です。
お礼
何度もありがとうございます。 適切にプリペアドステートメントを使っていれば、 どんな文字列を打ち込まれようとも大丈夫だい! という風に解釈いたしました。
- agunuz
- ベストアンサー率65% (288/438)
>「そのまま」ということは、適切にエスケープすることなく、 >という意味でしょうか。 > >つまり、マズイ という意味? あ、いえ「普通の文字列と同じように」扱えるということです。たとえばphpスクリプトでは、文字列型の変数の内容がテキスト(asiiなのか日本語なのかも不問)であってもバイナリであっても同じように扱ってかまいません。 当然ですが『適切にエスケープする』ことが前提です。
お礼
回答をありがとうございます。 バイナリの件ですが、 「'」を含まない文字列の中で、 もし、下記の「入力値」の所に入れられてしまうと、 SELECT * FROM users WHERE name = '(入力値)'; SQLインジェクションが成立してしまうような、 そんな文字列はありますでしょうか? あるなら、バイナリ文字でしょうか?! もし、そうであるなら、 そのバイナリ文字さん達は、どうやってエスケープすればいいんだ?! 以上が、私が質問したかったことになります。 またよろしければ、教えてください。(ぺこり
- shimix
- ベストアンサー率54% (865/1590)
>ちなみに、その『プレースホルダを使う場合』においては、 >エスケープ処理は、どのように、なされているのでしょうか? 基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることになります(各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などのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。
お礼
回答をありがとうございます。 また理解が深まりました。 >基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることに >データベース関係のエスケープ処理の多くは「文字列型は単引用符で括る」ことを前提に書かれています。 ということは、SQL文で文字列型を扱う際には、慣例に従い、 「単引用符で括る」ようにしておいた方が良い、ということになりますね。 これを、二重引用符で括るようなコーディングを続けていると、 ↓ 「SQL文の文字列型を二重引用符で括る」 かつ 「悪意ある二重引用符を含む値をユーザから受け取る」 ↓ その結果、 プリペアドステートメントを使っていても、 もともと、二重引用符にはエスケープはされないため、 最悪の場合、SQLインジェクションが成立してしまう、 ということになりますものね。 >SQLite3のescapeに関する下記のノートなどを読むと一目瞭然 二重引用符はエスケープされないから気をつけろ! (二重引用符をエスケープしない仕様になっている理由などもゴニョゴニョ。) みたいなことが英語で書かれていましたね。 本件と非常に関わりの深いノートでした。 >またBlobなどのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。 すみません(汗) ここの意味が、能力の低い私にはよく分かりませんでした。 >バイナリデータもそのまま扱います 「そのまま」ということは、適切にエスケープすることなく、 という意味でしょうか。 つまり、マズイ という意味? >これが出来ないデータベース 「これ」とは、何でしょう。 バイナリデータをそのまま扱うこと。 ? それとも、 バイナリデータをそのまま扱わず、エスケープしてから扱うこと。 ? それとも、 また別のことでしょうか。 >これが出来ないデータベースの方が少数派 出来ない方が、マズイ という言い方なのですよね、きっと。 (そんなマズイDBの方が少数派ですよ、という風に理解しました。) もし、またよろしければ、教えて下さい。
- muuming2001
- ベストアンサー率23% (202/847)
SELECT * FROM users WHERE name = "(入力値)"; DBによっても違うかもしれないけど、そもそも上記SQLは通るの? http://www.dbonline.jp/sqlite/type/index4.html
お礼
回答をありがとうございます。 >そもそも上記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
お礼
回答をありがとうございます。 >逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。 ですよね! つまり、 $sql = 'SELECT * FROM users WHERE name = "(入力値)"'; というようにコーディングをしている場合には、 「二重引用符のエスケープは必須」ということですよね。 >結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいい なるほど。そういう考え方があるわけですね。 ちなみに、その『プレースホルダを使う場合』においては、 エスケープ処理は、どのように、なされているのでしょうか? システムが、渡されてきた文字列を見ながら、適宜、 SQL文内における「文字列を括る引用符」を、 適切にチョイスしてくれる、ということでしょうか。 (つまり、人間が手動でエスケープ処理をしなくてよく、 すべて、システムにお任せできてしまう?) 「'」だろうが、「"」だろうが、 また、「バイナリセーフじゃない文字列」だろうが、 そのまま、システムに丸投げできてしまう、 ということでしょうか。 ※「バイナリセーフじゃない文字」までは、 さすがに丸投げはできないかもしれませんが・・・。 (さらに、色々と聞いてしまい、すみません。) もし、宜しければ、教えて下さい。