3

SQLのパラメーター化は、最近のホットなトピックであり、正当な理由がありますが、それは本当に適切にエスケープする以外に何かをしますか?

パラメータ化エンジンは、データをクエリ文字列に挿入する前に、データが適切にエスケープされていることを確認するだけでよいと想像できますが、それだけで十分ですか?たとえば、次のように、接続で別のことを行う方が理にかなっています。

> Sent data. Formatting: length + space + payload
< Received data
-----
> 69 SELECT * FROM `users` WHERE `username` LIKE ? AND `creation_date` > ?
< Ok. Send parameter 1.
> 4 joe%
< Ok. Send parameter 2.
> 1 0
< Ok. Query result: [...]

この方法では、SQLインジェクションの問題が単純に解消されるため、エスケープによって回避する必要はありません。パラメータ化がどのように機能するかを考えることができる他の唯一の方法は、パラメータをエスケープすることです。

// $params would usually be an argument, not in the code like this
$params = ['joe%', 0];

// Escape the values
foreach ($params as $key=>$value)
    $params[$key] = mysql_real_escape_string($value);

// Foreach questionmark in the $query_string (another argument of the function),
// replace it with the escaped value.
$n = 0;
while ($pos = strpos($query_string, "?") !== false && $n < count($params)) {
    // If it's numeric, don't use quotes around it.
    $param = is_numeric($params[$n]) ? $params[$n] : "'" . $params[$n] . "'";
    // Update the query string with the replaced question mark
    $query_string = substr($query_string, 0, $pos) //or $pos-1? It's pseudocode...
                  . $param
                  . substr($query_string, $pos + 1);
    $n++;

後者の場合、私はまだ自分のサイトをパラメータ化に切り替えるつもりはありません。私が見ることができる利点はありません、それはただ別の強い対弱い変数タイピングの議論です。強い型付けは、コンパイル時にさらに多くのエラーをキャッチする可能性がありますが、他の方法では困難なことを実際には可能にしません。このパラメーター化と同じです。(間違っている場合は訂正してください!)


アップデート:

  • これはSQLサーバー(およびクライアントにも依存しますが、クライアントは可能な限り最高の手法を使用していると思います)に依存することはわかっていましたが、ほとんどの場合、MySQLを念頭に置いていました。ただし、他のデータベースに関する回答も歓迎します(そして歓迎しました)。
  • 私が答えを理解している限り、パラメーター化は実際にデータを単にエスケープする以上のことを行います。これは実際にはパラメーター化された方法でサーバーに送信されるため、単一のクエリ文字列としてではなく、変数が分離されます。
  • これにより、サーバーはさまざまなパラメーターを使用してクエリを保存および再利用できるようになり、パフォーマンスが向上します。

私はすべてを手に入れましたか?私がまだ興味を持っていることの1つは、MySQLにこれらの機能があるかどうか、そしてクエリの再利用が自動的に行われるかどうか(そうでない場合は、これをどのように行うことができるか)です。

また、誰かがこのアップデートを読んだときにコメントしてください。それが質問か何かにぶつかるかどうかはわかりません...

ありがとう!

4

3 に答える 3

7

コマンドとパラメーターの処理方法は、特定のデータベースエンジンとクライアントライブラリによって異なると確信しています。

ただし、SQL Serverの経験から言えば、ADO.NETを使用してコマンドを送信するときにパラメーターが保持されることがわかります。それらはステートメントに組み込まれていません。たとえば、SQL Profilerを使用する場合、次のようなリモートプロシージャコールが表示されます。

exec sp_executesql N'INSERT INTO Test (Col1) VALUES (@p0)',N'@p0 nvarchar(4000)',@p0=N'p1'

SQLインジェクションを防ぐ以外にも、パラメーター化には他の利点があることに注意してください。たとえば、ステートメントは常に同じであるため(パラメーター値のみが変更されるため)、クエリエンジンはパラメータ化されたクエリに対してクエリプランを再利用する可能性が高くなります。

更新への応答: クエリのパラメータ化は非常に一般的であるため、MySQL(および実際にはすべてのデータベースエンジン)が同様に処理することを期待します。

MySQLプロトコルのドキュメントに基づくと、プリペアドステートメントはCOM_PREPAREパケットとCOM_EXECUTEパケットを使用して処理されているようです。これらのパケットは、バイナリ形式の個別のパラメータをサポートしています。すべてのパラメーター化されたステートメントが準備されるかどうかは明確ではありませんが、準備されていないステートメントは、パラメーターのサポートについて言及されていないCOM_QUERYによって処理されるように見えます。

疑わしい場合:テストします。有線で何が送信されているかを本当に知りたい場合は、Wiresharkなどのネットワークプロトコルアナライザを使用してパケットを確認してください。

内部での処理方法や、特定のエンジンに現在提供されているかどうかに関係なく、パラメーターを使用しないことで得られるメリットはほとんどありません(何もありませんか?)。

于 2012-08-11T21:11:13.733 に答える
3

パラメータ化されたクエリは、パラメータ化されたクエリとしてSQL実装に渡されます。実装が自身の連結にフォールバックすることを決定しない限り、パラメータがクエリ自体に連結されることはありません。パラメータ化されたクエリは、エスケープの必要性を回避し、クエリが汎用であり、コンパイルされた形式のクエリがデータベースサーバーによってすでにキャッシュされている可能性が高いため、パフォーマンスが向上します。

于 2012-08-11T21:10:17.980 に答える
2

正解は、「問題の特定の実装で実装されている方法に関係なく実装されている」ということです。数十のデータベース、数十のアクセスレイヤーがあり、場合によっては、同じアクセスレイヤーが同じコードを処理するための複数の方法があります。

したがって、ここに正しい答えは1つではありません。

1つの例は、プリペアドステートメントではないクエリでNpgsqlを使用する場合、ほとんど正しくエスケープすることです(ただし、Postgresqlでのエスケープには、エスケープについて知っている人が見逃すエッジケースがいくつかあり、Npgsqlはそれらをすべてキャッチします) 、それでもゲイン)。プリペアドステートメントを使用すると、パラメータがプリペアドステートメントパラメータとして送信されます。したがって、あるケースでは、別のケースよりもクエリプランの再利用が可能になります。

同じフレームワーク(ADO.NET)のSQLServerドライバーは、クエリをsp_executesqlの呼び出しとして渡します。これにより、クエリプランの再利用が可能になります。

それだけでなく、いくつかの理由から、エスケープの問題はまだ検討する価値があります。

毎回同じコードです。自分自身を逃れている場合は、毎回同じコードを使って逃げているか(つまり、他の人の同じコードを使用することにマイナス面があるわけではありません)、それぞれがスリップアップするリスクがあります。時間。

彼らはまた、逃げないのが得意です。'たとえば、文字を探す数字の文字列表現のすべての文字を調べる意味はありません。しかし、不必要なリスク、または合理的なマイクロ最適化としてカウントを逃れることはありません。

ええと、「合理的なマイクロ最適化」それ自体は、2つのことのうちの1つを意味します。後で書くことも読むことも精神的な努力を必要としないか(この場合はあなたもそうかもしれません)、またはわずかな節約が合計されるほど頻繁にヒットし、簡単に実行できます。

(関連して、高度に最適化されたエスケープャーを作成することもより理にかなっています-関係する文字列置換の種類は、置換の最も一般的なアプローチが少なくとも一部の言語の他のアプローチほど速くない場合のようなものですが、最適化は、メソッドが非常に頻繁に呼び出される場合にのみ意味があります)。

パラメータの型チェックを含むライブラリがある場合(型に基づいて使用される形式、または検証によって、どちらもそのようなコードで一般的です)、これらのライブラリは大量使用を目的としているため、簡単に実行できます。 、それは合理的なマイクロオプトです。

8パラメーター呼び出しのパラメーター番号7に文字が含まれる可能性があるかどうかを毎回考えている場合は、そう'ではありません。

必要に応じて、他のシステムへの変換も簡単です。上記の2つの例をもう一度見ると、作成されたクラスを除いて、SQL-ServerとPostgresqlのエスケープルールは異なりますが、System.Data.SqlClientとほぼ同じコードを使用できます。Npgsqlまた、バイナリ文字列、日時、および共通する他のいくつかのデータ型の形式もまったく異なります。

また、これを「ホットトピック」と呼ぶことに同意することはできません。少なくとも10年以上にわたって、十分に確立されたコンセンサスがありました。

于 2012-08-11T21:46:38.217 に答える