アプリ版:「スタンプのみでお礼する」機能のリリースについて

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文につっこんでも大丈夫なのでしょうか?

A 回答 (5件)

SQL文の中で「文字列」を単引用符で括っているなら、その中にある二重引用符は「単なる文字」としてしか認識されません。

なのでエスケープする必要はありません。逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。

「適切なエスケープをする」というのは、そういうことです。

結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいいということになります。
    • good
    • 0
この回答へのお礼

回答をありがとうございます。

>逆にSQL文で文字列を二重引用符で括って渡しているなら二重引用符のエスケープは必須です。

ですよね!

つまり、

$sql = 'SELECT * FROM users WHERE name = "(入力値)"';


というようにコーディングをしている場合には、
「二重引用符のエスケープは必須」ということですよね。



>結論としては『プレースホルダを使って』文字列を括る引用符も含めてシステム(ドライバ)に任せた方がいい

なるほど。そういう考え方があるわけですね。

ちなみに、その『プレースホルダを使う場合』においては、
エスケープ処理は、どのように、なされているのでしょうか?

システムが、渡されてきた文字列を見ながら、適宜、
SQL文内における「文字列を括る引用符」を、
適切にチョイスしてくれる、ということでしょうか。
(つまり、人間が手動でエスケープ処理をしなくてよく、
すべて、システムにお任せできてしまう?)

「'」だろうが、「"」だろうが、
また、「バイナリセーフじゃない文字列」だろうが、
そのまま、システムに丸投げできてしまう、
ということでしょうか。

※「バイナリセーフじゃない文字」までは、
さすがに丸投げはできないかもしれませんが・・・。


(さらに、色々と聞いてしまい、すみません。)

もし、宜しければ、教えて下さい。

お礼日時:2013/02/19 14:06

#あ、先に書かれた(汗



thx.>agunuzさん

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

何度もありがとうございます。

適切にプリペアドステートメントを使っていれば、
どんな文字列を打ち込まれようとも大丈夫だい!

という風に解釈いたしました。

お礼日時:2013/02/19 22:57

>「そのまま」ということは、適切にエスケープすることなく、


>という意味でしょうか。
>
>つまり、マズイ という意味?

あ、いえ「普通の文字列と同じように」扱えるということです。たとえばphpスクリプトでは、文字列型の変数の内容がテキスト(asiiなのか日本語なのかも不問)であってもバイナリであっても同じように扱ってかまいません。

当然ですが『適切にエスケープする』ことが前提です。
    • good
    • 0
この回答へのお礼

回答をありがとうございます。

バイナリの件ですが、
「'」を含まない文字列の中で、
もし、下記の「入力値」の所に入れられてしまうと、

SELECT * FROM users WHERE name = '(入力値)';

SQLインジェクションが成立してしまうような、
そんな文字列はありますでしょうか?

あるなら、バイナリ文字でしょうか?!

もし、そうであるなら、
そのバイナリ文字さん達は、どうやってエスケープすればいいんだ?!


以上が、私が質問したかったことになります。


またよろしければ、教えてください。(ぺこり

お礼日時:2013/02/19 22:55

>ちなみに、その『プレースホルダを使う場合』においては、


>エスケープ処理は、どのように、なされているのでしょうか?

基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることになります(各DBのドライバで微妙に違う部分もあります)。

何故データベースによって違いがあるかといえば、それはエスケープした結果を各データベースがどう扱うかが異なるからです。不要な部分までエスケープした結果、正しく格納できなくなったら困りますので。mysql_real_escape_stringなどは両方ともエスケープしますが、これはその状態で渡された文字列をMySQLがキチンと戻して格納するからです。

http://www.php.net/manual/ja/function.mysql-real …

データベース関係のエスケープ処理の多くは「文字列型は単引用符で括る」ことを前提に書かれています。SQLite3のescapeに関する下記のノートなどを読むと一目瞭然でしょう。

http://www.php.net/manual/ja/sqlite3.escapestrin …

またBlobなどのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。
    • good
    • 0
この回答へのお礼

回答をありがとうございます。
また理解が深まりました。

>基本的には文字列は単引用符で括りますので単引用符がエスケープ処理されることに
>データベース関係のエスケープ処理の多くは「文字列型は単引用符で括る」ことを前提に書かれています。

ということは、SQL文で文字列型を扱う際には、慣例に従い、
「単引用符で括る」ようにしておいた方が良い、ということになりますね。

これを、二重引用符で括るようなコーディングを続けていると、



「SQL文の文字列型を二重引用符で括る」
かつ
「悪意ある二重引用符を含む値をユーザから受け取る」



その結果、

プリペアドステートメントを使っていても、
もともと、二重引用符にはエスケープはされないため、
最悪の場合、SQLインジェクションが成立してしまう、

ということになりますものね。


>SQLite3のescapeに関する下記のノートなどを読むと一目瞭然

二重引用符はエスケープされないから気をつけろ!
(二重引用符をエスケープしない仕様になっている理由などもゴニョゴニョ。)
みたいなことが英語で書かれていましたね。
本件と非常に関わりの深いノートでした。


>またBlobなどのバイナリデータもそのまま扱います(プレースホルダを使う・使わないにかかわらず、これが出来ないデータベースの方が少数派だと思います)。

すみません(汗)
ここの意味が、能力の低い私にはよく分かりませんでした。


>バイナリデータもそのまま扱います

「そのまま」ということは、適切にエスケープすることなく、
という意味でしょうか。

つまり、マズイ という意味?


>これが出来ないデータベース

「これ」とは、何でしょう。

バイナリデータをそのまま扱うこと。 ?
それとも、
バイナリデータをそのまま扱わず、エスケープしてから扱うこと。 ?
それとも、
また別のことでしょうか。


>これが出来ないデータベースの方が少数派

出来ない方が、マズイ という言い方なのですよね、きっと。
(そんなマズイDBの方が少数派ですよ、という風に理解しました。)

もし、またよろしければ、教えて下さい。

お礼日時:2013/02/19 19:25

SELECT * FROM users WHERE name = "(入力値)";



DBによっても違うかもしれないけど、そもそも上記SQLは通るの?

http://www.dbonline.jp/sqlite/type/index4.html
    • good
    • 0
この回答へのお礼

回答をありがとうございます。

>そもそも上記SQLは通るの?

ここで話題にしている「SQLite3のDB」では、
SQL文の中で文字列をダブルクオーテーションで、
くくることは出来るようです。

参考:
http://programing.dip.jp/index.php?SQLite%2F%E3% …

お礼日時:2013/02/19 13:47

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!