2009-08-21 18 views
34

PDO準備済みステートメントの使用が始まったばかりでなく、理解しているとおり、すべてのエスケープ/セキュリティを行います。PDO準備ステートメントの安全性

たとえば、$ _POST ['title']がフォームフィールドであると仮定します。

$title = $_POST['title']; 
$query = "insert into blog(userID, title) values (?, ?)" 
$st = $sql->prepare($query); 
$st->bindParam(1, $_SESSION['user']['userID'], PDO::PARAM_INT); 
$st->bindParam(2, $title); 
$st->execute(); 

これは本当に安全ですか?私は何か他のことをしなくてはなりませんか?それ以外に何を考慮する必要がありますか?

ありがとうございました。

答えて

66

厳密に言えば、実際にはパラメータ値はクエリ文字列には挿入されないため、エスケープする必要はありません。

prepare()を呼び出したときにクエリがデータベースサーバーに送信され、後で​​を呼び出したときにパラメータ値が送信されるという仕組みです。したがって、それらはテキスト形式のクエリとは別に保存されます。 SQLインジェクションの機会はありません(PDO::ATTR_EMULATE_PREPARESがfalseの場合)。

はい、クエリパラメータは、そのようなセキュリティ上の脆弱性を回避するのに役立ちます。

セキュリティ上の脆弱性に対する100%の保証はありますか?いいえ、もちろんです。ご存知のように、クエリパラメータはSQL式の1つのリテラル値の代わりになります。

SELECT * FROM blog ORDER BY ?; 

することができます:あなたは、テーブル名や動的な列名を作るためにパラメータを使用することはできません

SELECT * FROM blog WHERE userid IN (?); 

:あなたは、たとえば、値のリストについては、単一のパラメータの代替をすることはできませんですから、前prepare()呼び出しに文字列としてクエリを操作する必要がかなりの数の例がある

SELECT EXTRACT(? FROM datetime_column) AS variable_datetime_element FROM blog; 

:「Tは、SQL構文の他のタイプのためのパラメータを使用します。このような場合、SQLインジェクションを避けるためにコードを慎重に記述する必要があります。

+2

これは非常に良い情報でした。ありがとうございました! – sqram

+0

また 'LIKE? 'は有効ですが、マッチングに使用する文字をエスケープする必要があります。 –

+0

「SQLインジェクションの機会はありません(PDO :: ATTR_EMULATE_PREPARESはfalseです)」とは、PDOエミュレートされた準備がdbドライバのネイティブな準備と同じくらい安全ではないということですか?もしそうなら、なぜですか? –

2

SQLインジェクションに関しては、特にPDO :: PARAM_INTのような定数を使用すると、これが最も安全な方法だと思います。

+6

この '特別な'には、明確化IMOが必要です。おそらく95%安全だとは言わないが、定数を使うと100%安全です。定数なしで100%安全でない場合、安全ではありません。100%の場合、定数では特に安全ではありません。 定数の使用と使用しない場合の安全上の違いは何ですか? – koen

9

SQLインジェクションから安全です。

それはより安全ではありませんカップルの事:

  • サービス拒否(作成される行の過剰な量を引き起こす)
  • クロスサイトスクリプティング攻撃(タイトルが今までに戻って別のユーザーにエコーされている場合)

セキュリティは単にSQLインジェクションを防止するだけではありません。

+0

お寄せください。タイトルが別のユーザーにエコーバックされたらどういう意味ですか? – sqram

+3

ブログの投稿のタイトルをデータベースに保存し、他のユーザーがこれらの投稿を閲覧できるとします。悪意のあるユーザーがサイトの他のユーザーに表示されるように悪質なスクリプトをページに埋め込むためのHTMLを含むタイトルを作成できるという点で、クロスサイトスクリプティング攻撃の可能性があります。 – Yuliy

関連する問題