web-dev-qa-db-ja.com

bind_paramは何を達成しますか?

私はSQLインジェクションを回避することについて学んでいて、少し混乱しています。

Bind_paramを使用する場合、目的がわかりません。マニュアルページで、私はこの例を見つけました:

$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);

$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;

さて、これらの4つの変数がユーザー入力されたと仮定すると、これがSQLインジェクションをどのように防ぐのか理解できません。私の理解では、彼らはまだそこに好きなものを入力することができます。

そこに'sssd'の説明もありません。それは何をするためのものか?それが安全な理由ですか?

最後の質問:mysqli_real_escape_stringが非推奨であるという別の質問を読みましたが、マニュアルにはそれが記載されていません。どのように非推奨になりましたか?なんらかの理由で特殊文字をエスケープできなくなりましたか?

注:この質問はbind_paramの機能を説明していますが、なぜそれがより安全で保護されているのかまだわかりません。 Bind_paramの説明

13
EveyPortman

さて、これらの4つの変数がユーザー入力されたと仮定すると、これがSQLインジェクションをどのように防ぐのか理解できません。私の理解では、彼らはまだそこに好きなものを入力することができます。

主な原則は、データベースサーバーに安全なクエリを送信するために設計されたプリペアドステートメントを使用することです。これは、実際のクエリの一部ではないユーザー入力をエスケープし、(where句)を指定せずにクエリをチェックすることで実行できます。パラメータを使用する前のクエリの有効性。

この質問から: Mysqliが準備されたクエリを送信する間、PDOはMySQLに生のクエリを送信します。どちらも同じ結果を生成します

_$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) {
$stmt->bind_param("i", $user);
$user = "''1''";
_

サーバーログ:

_  130802 23:39:39   175 Connect   ****@localhost on testdb
    175 Prepare   SELECT * FROM users WHERE username =?
    175 Execute   SELECT * FROM users WHERE username =0
    175 Quit
_

プリペアドステートメントを使用することにより、dbサーバーはパラメーターなしでクエリをチェックします。この段階で、パラメーターをバインドする前にエラーを検出できます。クエリが有効な場合は、クエリを完了するためにパラメーターもサーバーに送信されます。

From PHP Manual http://php.net/manual/en/mysqli.quickstart.prepared-statements.php

エスケープとSQLインジェクション

バインドされた変数は、サーバーによって自動的にエスケープされます。サーバーは、エスケープされた値を適切な場所でステートメントテンプレートに挿入してから実行します。適切な変換を作成するには、バインドされた変数のタイプに関するヒントをサーバーに提供する必要があります。詳細については、mysqli_stmt_bind_param()関数を参照してください。

..

また、そこに「sssd」の説明が見つかりません。それは何をするためのものか?それが安全な理由ですか?

答えはここにあります: http://php.net/manual/en/mysqli-stmt.bind-param.php

_i
corresponding variable has type integer

d
corresponding variable has type double

s
corresponding variable has type string

b
corresponding variable is a blob and will be sent in packets
_

最後の質問:mysqli_real_escape_stringが非推奨であるという別の質問を読みましたが、マニュアルにはそれが記載されていません。どのように非推奨になりましたか?なんらかの理由で特殊文字をエスケープできなくなりましたか?

参考にできますか? (mysql_real_escape_string())と誤解されたと思います

17
user1646111

プリペアドステートメントを使用することで、SQLクエリをユーザーが入力したデータから分離します。入力データの代わりに、SQLクエリにプレースホルダー( '?' char)を配置します。次に、「mysqli :: prepare」メソッドを使用して、クエリをDBMSサーバー(例:MySQL)に送信します。そのため、サーバーはすべてに問題がないことを確認し、問題がない場合は入力データを待ちます。今ではすでにあなたのクエリを知っています。入力データがクエリにバインドされるのを待つ必要があります。

この時点で、「bind_param」が実行され、プレースホルダーがユーザーが入力したデータにバインドされます。 bind_paramはデータをプレースホルダーにのみバインドし、クエリは変更しないことに注意してください。したがって、元のSQLクエリを変更する方法はありません。これは、prepareメソッドを使用して既にサーバーに送信されており、SQLクエリと入力データを別々に送信しているため、ユーザーが入力したデータがクエリに干渉しないためです。

とにかく...

SQLでプリペアドステートメントを使用する実際の目的は、クエリからデータを分離することではなく、クエリの処理コストを削減することです。そもそも使用するように設計された方法ではなく、現在使用されている方法です。

「sssd」は「string」、「string」、「string」、「double」を表します。実際、$ codeは文字列、$ languageは文字列、$ officialは文字列、$ percentはdouble型です。

mysqli_real_escape_stringは非推奨ではありませんが、mysql_real_escape_stringは非推奨です(最初のものはmysqlIで、私は「改善された」を表します)。

11