web-dev-qa-db-ja.com

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();

これは本当に安全ですか?他に何かする必要がありますか?他に何を考慮に入れる必要がありますか?

ありがとう。

42
sqram

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

クエリパラメータが機能する方法は、prepare()を呼び出したときにクエリがデータベースサーバーに送信され、後でexecute()を呼び出したときにパラメータ値が送信されることです。したがって、それらはクエリのテキスト形式から分離されています。 SQLインジェクションの機会は決してありません(_PDO::ATTR_EMULATE_PREPARES_がfalseの場合)。

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

それらはセキュリティの脆弱性に対して100%の証拠ですか?いいえ、もちろん違います。ご存知かもしれませんが、クエリパラメータはSQL式の単一のリテラル値の代わりになります。値のリストの代わりに単一のパラメーターを作成することはできません。次に例を示します。

_SELECT * FROM blog WHERE userid IN ( ? );
_

パラメータを使用してテーブル名または列名を動的にすることはできません。

_SELECT * FROM blog ORDER BY ?;
_

他のタイプのSQL構文にパラメーターを使用することはできません。

_SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog;
_

したがって、prepare()呼び出しの前に、クエリを文字列として操作しなければならない場合がかなりあります。このような場合でも、SQLインジェクションを回避するために、慎重にコードを記述する必要があります。

79
Bill Karwin

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

安全ではないことがいくつかあります。

  • サービス拒否(過剰な量の行が作成される原因)
  • クロスサイトスクリプティング攻撃(タイトルが別のユーザーにエコーバックされた場合)

セキュリティは、SQLインジェクションを防ぐだけではありません。

11
Yuliy

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

2
Alix Axel

XSSが言及されているので、この入力クリーニングクラスなどを使用して検討するのも良いと思います http://www.phpclasses.org/browse/package/2189.html XSS攻撃。

1
Rob