SQLインジェクション防止メカニズムがパラメーター化されたクエリを使用する方向に進化したのはなぜですか?


59

私の考えでは、SQLインジェクション攻撃は次の方法で防止できます。

  1. 入力を慎重にスクリーニング、フィルタリング、エンコードする(SQLへの挿入前)
  2. 使用して準備された文 /パラメータ化クエリを

それぞれに長所と短所があると思いますが、なぜ#2が離陸し、インジェクション攻撃を防ぐための事実上の方法であると見なされるようになったのですか?単に安全でエラーが発生しにくいのですか、それとも他の要因がありましたか?

私が理解しているように、#1が適切に使用され、すべての警告が処理されれば、#2と同じくらい効果的です。

サニタイズ、フィルタリング、エンコード

私の側では、サニタイズフィルタリング、およびエンコードの意味が混乱していました。この場合、サニタイズとフィルタリングは入力データを変更または破棄する可能性があることを理解していますが、エンコードはデータをそのまま保持しますが、エンコードしますインジェクション攻撃を避けるために適切に。データをエスケープすることは、それをエンコードする方法と考えることができると信じています。

パラメータ化されたクエリとエンコーディングライブラリ

parameterized queriesとの概念がencoding libraries相互に交換可能に扱われている答えがあります。私が間違っている場合は修正しますが、私はそれらが異なっているという印象を受けています。

私が理解しているのは、encoding librariesどんなに優れていても、SQL「プログラム」を変更する可能性は常にあるということです。

Parameterized queries 一方、SQLプログラムをRDBMSに送信すると、RDBMSはクエリを最適化し、クエリ実行プランを定義し、使用するインデックスを選択するなどして、RDBMS内の最後のステップとしてデータをプラグインします。自体。

エンコーディングライブラリ

  data -> (encoding library)
                  |
                  v
SQL -> (SQL + encoded data) -> RDBMS (execution plan defined) -> execute statement

パラメータ化されたクエリ

                                               data
                                                 |
                                                 v
SQL -> RDBMS (query execution plan defined) -> data -> execute statement

歴史的意義

いくつかの回答では、歴史的に、パラメーター化されたクエリ(PQ)はパフォーマンス上の理由で作成され、インジェクション攻撃の前にエンコードの問題をターゲットにしたと言われています。ある時点で、PQはインジェクション攻撃に対しても非常に効果的であることが明らかになりました。私の質問の精神を維持するために、なぜPQが選択の方法であり続け、SQLインジェクション攻撃の防止に関して、他のほとんどの方法よりも優れているのでしょうか?


1
コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
maple_shaft

23
準備されたステートメントは、SQLインジェクション攻撃の進化の結果ではありません。彼らは最初からそこにいました。あなたの質問は、誤った予見に基づいています。
user207421

4
あなたが悪者よりも賢いと思うなら、#1に行く
パパラッチ

1
「なぜPQが選択の方法であり続けたのか」という理由は、PQが最も簡単で堅牢だからです。さらに、前述のPQのパフォーマンス上の利点もあります。欠点はありません。
ポールドレイパー

1
セキュリティコンテキストでのSQLインジェクションの問題ではない場合でも、クエリの実行方法の問題に対する正しいソリューションであるためです。エスケープが必要で、コマンドで帯域内データを使用するフォームは、エラーが発生しやすく、直感に反し、間違って使用すると破損するため、常に設計上のバグです。シェルスクリプトも参照してください。
R ..

回答:


147

問題は、#1では、作業対象のSQLバリアント全体を効果的に解析および解釈する必要があるため、実行すべきでないことを実行しているかどうかがわかることです。また、データベースを更新するときに、そのコードを最新の状態に保ちます。どこでもあなたのクエリの入力を受け付けます。それを台無しにしないでください。

そのため、そのようなことはSQLインジェクション攻撃を阻止しますが、実装するのはとてつもなく費用がかかります。


60
@dennis-さて、SQLバリアントの引用とは何ですか?「? '?」?U + 2018?\ u2018?式を分離するコツはありますか?サブクエリは更新できますか?考慮すべき点がたくさんあります。
Telastyn

7
@DennisのすべてのDBエンジンには、文字列内の文字をエスケープするなど、独自の方法があります。特に、アプリケーションが複数のDBエンジンで動作する必要がある場合や、同じエンジンの将来のバージョンと互換性があり、悪用される可能性のあるマイナーなクエリ構文を変更する必要がある場合、プラグインする多くの穴があります。

12
準備済みステートメントのもう1つの利点は、異なる値で同じクエリを再実行する必要がある場合に得られるパフォーマンスの向上です。また、準備済みステートメントは、値がnull文字列、文字列、数値のいずれであるかを認識し、それに応じて動作します。これはセキュリティに非常に適しています。また、クエリを1回実行した場合でも、DBエンジンは既に最適化されています。キャッシュされている場合はさらに良いです!
イスマエルミゲル

8
@Dennisヘンリー・ヌル氏は、これを正しく行ってくれたことに感謝します。
マチューギンドン

14
@Dennis名は関係ありません。問題は姓にあります。Stack OverflowProgrammers.SEFox SportsWiredBBCなど、Googleのクイック検索で見つけられるその他のものを参照してください;
Mathieu Guindon

80

オプション1は解決策ではないからです。スクリーニングとフィルタリングとは、無効な入力を拒否または削除することを意味します。ただし、入力は有効かもしれません。たとえば、アポストロフィは「O'Malley」という名前の有効な文字です。SQLで使用する前に正しくエンコードする必要があります。これが準備済みステートメントの機能です。


メモを追加すると、機能的に類似した独自のコードをゼロから作成するのではなく、基本的に標準ライブラリ関数を使用する理由を尋ねているようです。独自のコードを記述するよりも、常に標準ライブラリソリューションを優先する必要があります。作業量が少なく、メンテナンスが容易です。これはどの機能にも当てはまりますが、特にセキュリティに敏感なものの場合、自分で車輪を再発明することはまったく意味がありません。


2
それだけです(そして、それは他の2つの答えの欠落部分でしたので、+ 1です)。質問がどのように定式化されるかを考えると、それはユーザー入力をサニタイズすることではなく、「入力のフィルタリング(挿入前)」という質問を引用します。質問が入力をサニタイズすることである場合、ライブラリに実行させるのではなく、なぜ自分でそれを行うのでしょうか(一方で、実行計画をキャッシュする機会を失います)。
アルセニムルゼンコ

8
@Dennis:サニタイズまたはフィルタリングとは、情報を削除することです。エンコードとは、情報失うことなくデータの表現を変換することです。
ジャックB

9
@Dennis:フィルタリングとは、ユーザー入力を受け入れるか拒否することを意味します。たとえば、値が明らかに無効であるため、「Jeff」は「User's age」フィールドの入力としてフィルタリングされます。入力をフィルタリングする代わりに、たとえば一重引用符を置き換えるなどして変換を開始すると、パラメータ化されたクエリを使用するデータベースライブラリとまったく同じことを実行します。この場合、あなたの質問は単に「すべてのプロジェクトで車輪を再発明できるのに、なぜこの分野の専門家によって作成されたものを使用するのですか?」
Arseni Mourzenko

3
@Dennis:O\'Malleyスラッシュを使用して、適切な挿入のために引用符をエスケープしています(少なくとも一部のデータベースでは)。MS SQLまたはAccessでは、追加の引用符でエスケープできますO''Malley。自分でやらなければならない場合、あまり移植性がありません。
-AbraCadaver

5
私の名前がシステムによって完全に拒否された回数を説明することはできません。私の名前を使用しただけで、SQLインジェクションによって引き起こされるエラーを見たことがあります。ヘック、私は実際にバックエンドで何かを壊していたので、ユーザー名を変更するように頼まれました。
アレクサンダーオマラ

60

文字列処理を実行しようとしている場合、実際にはSQLクエリを生成していません。SQLクエリを生成できる文字列を生成しています。間接的なレベルがあるため、エラーやバグが発生する余地が大きくなります。ほとんどのコンテキストで、プログラムで何かとやり取りできることを考えると、本当に驚くべきことです。たとえば、リスト構造があり、アイテムを追加する場合、通常は行いません。

List<Integer> list = /* a list of 1, 2, 3 */
String strList = list.toString();   /* to get "[1, 2, 3]" */
strList = /* manipulate strList to become "[1, 2, 5, 3]" */
list = parseList(strList);

誰かがそれを提案するなら、あなたはそれはむしろばかげていると正しく答えるでしょう。

List<Integer> list = /* ... */;
list.add(5, position=2);

これは、概念レベルでデータ構造と相互作用します。その構造がどのように印刷または解析されるかに依存しません。これらは完全に直交する決定です。

最初のアプローチは最初のサンプルのようなものです(少し悪いだけです):必要なクエリとして正しく解析される文字列をプログラムで構築できると仮定しています。これは、パーサーと、一連の文字列処理ロジックに依存します。

準備済みクエリを使用する2番目のアプローチは、2番目のサンプルによく似ています。準備されたクエリを使用する場合、基本的には正当であるがいくつかのプレースホルダーを含む擬似クエリを解析し、APIを使用してそこにいくつかの値を正しく代入します。解析プロセスに関与しなくなり、文字列処理について心配する必要はありません。

一般に、概念レベルで物事とやり取りするのははるかに簡単で、エラーが発生しにくいです。クエリは文字列ではありません。クエリは、文字列を解析するか、プログラムで構築する(または他の方法で作成できる)ときに得られるものです。

ここでは、単純なテキスト置換を行うCスタイルのマクロと、任意のコード生成を行うLispスタイルのマクロの間には良い類似性があります。Cスタイルのマクロを使用すると、ソースコード内のテキストを置き換えることができます。つまり、構文エラーや誤解を招く動作を導入することができます。Lispマクロを使用すると、コンパイラが処理する形式でコードを生成します(つまり、コンパイラが到達する前にリーダーが処理する必要のあるテキストではなく、コンパイラが処理する実際のデータ構造を返します) 。ただし、Lispマクロを使用すると、解析エラーになるようなものを生成できません。たとえば、(let((ab)aを生成できません。

Lispマクロを使用しても、そこにあるはずの構造に必ずしも気付く必要はないため、依然として不正なコードを生成する可能性があります。たとえば、Lispでは、 (let((ab))a)は、「変数aの変数bの値への新しい字句バインディングを確立してから、aの値を返す」ことを意味し、(let(ab)a)は「変数aとbの新しい字句バインディングを確立し、両方をnilに初期化してから、aの値を返します。」どちらも構文的には正しいですが、意味は異なります。この問題を回避するには、よりセマンティックに対応した関数を使用して、次のようなことを行うことができます。

Variable a = new Variable("a");
Variable b = new Variable("b");
Let let = new Let();
let.getBindings().add(new LetBinding(a,b));
let.setBody(a);
return let;

そのようなものでは、構文的に無効なものを返すことは不可能であり、意図しないものを誤って返すことははるかに困難です。


良い説明!
マイクパートリッジ

2
あなたは「良い類推」で私を失ったが、前の説明に基づいて私は賛成した。:)
ワイルドカード

1
素晴らしい例!-また、追加することもできます。データ型によっては、解析可能な文字列を作成することが不可能または実行不可能な場合があります。-パラメータの1つがストーリードラフト(〜10.000文字)を含むフリーテキストフィールドである場合はどうなりますか?または、1つのパラメーターがJPG-Imageの場合はどうなりますか?-唯一の方法は、パラメーター化されたクエリ
ファルコ

実際、いいえ-準備されたステートメントがSQLインジェクションの防御として進化した理由に関するかなり悪い説明です。特に、コード例がJavaである場合、C / C ++が最新技術と見なされる時間枠でおそらくパラメータ化されたクエリが開発されたときはそうではありませんでした。SQLデータベースは、1970〜1980年の初期の時期に使用されるようになりました。人気のあるより高いレベルの言語の前の方法。ヘック、それらの多くがデータベースの操作を簡単にするために来たと言うでしょう(PowerBuilderの誰か?)
TomTom

実際、@ TomTomは、ほとんどのコンテンツに同意します。ここでは、セキュリティの側面について暗黙のうちに触れただけです。SOでは、多くのSPARQL(RDFクエリ言語、SQLといくつかの類似点)の質問に答えます。多くの人々は、パラメーター化されたクエリを使用するのではなく、文字列を連結するため問題に直面します。インジェクション攻撃がなくても、パラメータ化されたクエリはバグ/クラッシュを回避するのに役立ち、バグ/クラッシュもインジェクション攻撃ではない場合でもセキュリティの問題になる可能性があります。だから私は言うだろう以下、より:パラメータ化クエリはSQLインジェクションは問題ではなかった場合でも、優れている、と彼らは良いしている...
ジョシュア・テイラー

21

データベースはクエリのパラメーター化されていないバージョンをキャッシュできるため、オプション#2は一般的にベストプラクティスと見なされます。パラメータ化されたクエリは、SQLインジェクションの問題に数年前から存在します(私は信じています)。たった1石で2羽の鳥を殺すことができます。


10
SQLインジェクションは、SQLが最初に発明されてからの問題です。後で問題になりませんでした。
セルビー

9
@Servy理論的にははい。実際には、入力メカニズムがオンラインになったときに初めて実際の問題になり、だれでも攻撃できる巨大な攻撃対象となりました。
ヤンDoggen

8
Little Bobby Tablesは、SQLインジェクションを活用するためにインターネットまたは大規模なユーザーベースのいずれかが必要であることに同意しません。そしてもちろん、ネットワークはSQLよりも前の日付なので、SQLが出てからネットワークを待つ必要はありません。はい、セキュリティの脆弱性がある少ないアプリケーションは、小さなユーザーベースを持っている場合、脆弱な、彼らはまだ、セキュリティの脆弱性だ、と人々はないデータベース自体が貴重なデータを持っている(と多くのときにそれらを利用する非常に初期のデータベースは非常に貴重なデータを持っていた唯一の人として、貴重なデータベースを使用すれば技術的に余裕があります。)
Servy

5
私の知る限り、動的SQLは比較的遅い機能でした。SQLの最初の使用は、ほとんどの場合、値のパラメーター(インとアウトの両方)でプリコンパイル/プリプロセスされているため、クエリのパラメーターはソフトウェアでのSQLインジェクションより前の場合があります(アドホック/ CLIクエリではない場合があります)。
マークロテベール

6
彼ら SQLインジェクションの認識に先立つかもしれません。
user253751

20

単純に言った:彼らはしませんでした。あなたの声明:

SQLインジェクション防止メカニズムがパラメーター化されたクエリを使用する方向に進化したのはなぜですか?

基本的に欠陥があります。パラメーター化されたクエリは、SQLインジェクションが少なくとも広く知られているよりもずっと長く存在していました。これらは一般に、LOB(基幹業務)アプリケーションが持つ通常の「検索用フォーム」機能での文字列集中を回避する方法として開発されました。多く-何年も-後に、誰かが上記の文字列操作に関するセキュリティ問題を発見しました。

25年前(インターネットが広く使用されていなかった-始まったばかり)にSQLを実行したことを覚えています。


ありがとう。文字列の連結を避ける必要があったのはなぜですか?それは便利な機能になるように思えます。誰かに問題がありましたか?
デニス

3
実際に2つ。第一に、それは必ずしも完全に些細なことではありません-なぜそれが必要でないときにメモリ割り当てなどに対処するのか。しかし、第二に、古代では、SQLデータベース側のパフォーマンスキャッシングはそれほど優れていませんでした。SQLのコンパイルは高価でした。1つのsql準備済みステートメント(パラメーターの元となる)を使用する副作用として、実行計画を再利用できます。SQL Serverは、自動パラメーター化を導入しました(パラメーターなしでもクエリプランを再利用するために-差し引かれて暗示されています)2000または2007のいずれか(IIRCの中間)。
トムトム

2
パラメータ化されたクエリを使用しても、文字列を連結する機能が失われることはありません。文字列の連結を行って、パラメーター化されたクエリを生成できます。機能が有用だからといって、特定の問題に対して常に適切な選択肢であるとは限りません。
ジミージェームズ

はい、しかし、私が言ったように、それらが発明されたときまでに、動的SQLはかなりまともなパフォーマンスヒットをもたらしました;)今日でも、SQLサーバーの動的SQLクエリプランは再利用されていないと言います(-hm-as以来間違っています)私は2000年から2007年の間にいくつかのポイントを言った-とても長いです)。その昔、SQLを複数回実行する場合はPREPAREDステートメントが本当に必要でした;)
TomTom

動的SQLのプランのキャッシュは、実際に中に、SQL Server 7.0へ追加されました1998 - sqlmag.com/database-performance-tuning/...
マイクDimmick

13

他のすべての良い答えに加えて:

#2が優れている理由は、コードからデータを分離するためです。#1では、データはコードの一部であり、そこからすべての悪いことが起こります。#1ではクエリを取得し、クエリがデータをデータとして理解するように追加のステップを実行する必要がありますが、#2ではコードとコードであり、データはデータです。


3
また、コードとデータを分離するということは、データベースベンダーが敵対的なコードインジェクションに対する防御策を作成してテストすることを意味します。したがって、無害なクエリとともにパラメータとして渡されたものがデータベースを破壊したり破壊したりした場合、データベース会社の評判は一線を画し、組織はそれらを訴えて勝つ可能性があります。また、そのコードに悪用可能なバグが含まれている場合、他の人のサイトではなく、あなたのサイトではなくすべてが壊れている可能性がかなり高いことを意味します。(セキュリティバグ修正を無視しないでください!)
nigel222

11

SQLインジェクション防御を提供することとは別に、パラメーター化されたクエリには、多くの場合、一度だけコンパイルされ、異なるパラメーターで複数回実行されるという追加の利点があります。

SQLデータベースの観点から見るselect * from employees where last_name = 'Smith'select * from employees where last_name = 'Fisher'、明らかに異なるため、個別の解析、コンパイル、および最適化が必要です。また、コンパイルされたステートメントの保存専用のメモリ領域内の個別のスロットを占有します。異なるパラメータ計算とメモリオーバーヘッドを持つ多数の同様のクエリを使用する負荷の高いシステムでは、かなりの量になる可能性があります。

その後、パラメーター化されたクエリを使用すると、多くの場合、パフォーマンスが大幅に向上します。


それが理論だと思います(パラメータ化されたクエリに使用される準備済みステートメントに基づく)。実際には、ほとんどの実装は1回の呼び出しでprepare-bind-executeを実行するだけなので、実際にはこれが実際にそうであるとは思わないので、明示的な手順を実行してステートメント(およびライブラリ-level prepareは多くの場合、実際のSQL レベルとはかなり異なりますprepare)。
-jcaron

次のクエリは、SQLパーサに異なりますSELECT * FROM employees WHERE last_name IN (?, ?)SELECT * FROM employees WHERE last_name IN (?, ?, ?, ?, ?, ?)
ダミアンジェリック

はい。彼らは持っています。1998年にMSがクエリプランのキャッシュをSQL Server 7に追加した理由は次のとおりです。
トムトム

1
@TomTom-クエリプランのキャッシングは、自動パラメータ化とは異なり、ヒントが表示されます。同様に、投稿する前に読んでください。
mustaccio

@mustaccio実際、少なくともMSは両方を同時に導入しました。
トムトム

5

待ってください、なぜですか?

オプション1は、あらゆるタイプの入力に対してサニタイズルーチンを作成する必要があることを意味しますが、オプション2は、作成/テスト/保守するためのエラーが少なく、コードが少なくなります。

ほぼ間違いなく、「すべての警告を処理する」ことは、あなたが思っているよりも複雑になる可能性があり、あなたの言語(たとえば、Java PreparedStatement)は、あなたが思っているよりも内部にあります。

準備済みステートメントまたはパラメーター化されたクエリはデータベースサーバーでプリコンパイルされるため、パラメーターが設定されている場合、クエリはSQL文字列ではないため、SQL連結は行われません。追加の利点は、RDBMSがクエリをキャッシュし、後続の呼び出しがパラメーター値が異なる場合でも同じSQLと見なされることです。一方、連結SQLでは、異なる値でクエリが実行されるたびにクエリが異なり、RDBMSはそれを解析する必要があります、実行計画を再度作成するなど。


1
JDBCはanithingをサニタイズしません。プロトコルにはパラメーターに特定の部分があり、DBは単にそのパラメーターを解釈しないため、パラメーターからテーブル名を設定できるのはこのためです。
タレックス

1
どうして?パラメータが解析または解釈されない場合、何かをエスケープする理由はありません。
タレックス

11
パラメータ化されたクエリがどのように機能するかについて、イメージが間違っていると思います。後で置換されるパラメーターの場合だけでなく、で置換されることもありません。DBMSは、クエリを「計画」、つまり結果を得るために実行する一連のステップに変換します。パラメータ化されたクエリでは、そのプランは関数のようなものです。実行するときに指定する必要がある変数が多数あります。変数が提供されるまでに、SQL文字列は完全に忘れられ、提供された値でプランが実行されます。
IMSoP

2
@IMSoPそれは私の誤解でした。SOstackoverflow.com/questions/3271249/…でこの質問に対して最も多く投票された2つの回答を見るとわかるように、これは一般的なものだと思います。私はそれについて読み、あなたは正しい。答えを編集しました。
Tulainsコルドバ

3
@TomTomこれはパフォーマンスには優れていますがセキュリティには何もしません。侵害された動的SQLの一部がコンパイルおよびキャッシュされるまでに、プログラムはすでに変更されています。動的なパラメータ化されていないSQLからプランを作成してデータ要素を渡すことは、完全なSQL文字列として提示される2つのクエリ間の類似性を抽象化するDBMSとは根本的に異なります。
IMSoP

1

理想的な「サニタイズ、フィルター、エンコード」アプローチがどのようになるか想像してみましょう。

サニタイズとフィルタリングは、特定のアプリケーションのコンテキストでは理にかなっているかもしれませんが、最終的には両方とも「このデータをデータベースに入れることはできません」と言うことになります。アプリケーションにとっては、それは良いアイデアかもしれませんが、データベースに任意の文字を格納する必要があるアプリケーションがあるため、一般的なソリューションとして推奨できるものではありません。

したがって、エンコードはそのままです。エスケープ文字を追加して文字列をエンコードする関数を作成することから始めて、自分で文字列を置き換えることができます。データベースごとに異なる文字をエスケープする必要があるため(一部のデータベースでは、両方ともの有効なエスケープシーケンスですが、他のデータベースではそう\'''はあり'ません)、この機能はデータベースベンダーが提供する必要があります。

しかし、すべての変数が文字列ではありません。整数または日付に置き換える必要がある場合があります。これらは文字列とは異なる方法で表されるため、異なるエンコード方法が必要になり(再び、これらはデータベースベンダーに固有である必要があります)、さまざまな方法でクエリに置き換える必要があります。

したがって、データベースがあなたのために置換を処理した場合、おそらく物事は簡単になるでしょう-クエリが期待するタイプ、データを安全にエンコードする方法、およびクエリに安全に置換する方法をすでに知っているので、心配する必要はありませんあなたのコードで。

この時点で、パラメーター化されたクエリを再発明しました。

また、クエリがパラメータ化されると、パフォーマンスの最適化や監視の簡素化などの新しい機会が開かれます。

エンコーディングを正しく実行することは難しく、エンコーディングを正しく実行することはパラメーター化と区別できません。

あなたが本当に建物クエリの方法として、文字列の補間のように、プラグイン可能な文字列の補間を持つ言語(スカラとES2015が頭に浮かぶ)がいくつかあり、その場合はそこに ある ライブラリ、あなたは文字列の補間のように見えるパラメータ化クエリを書いてみましょうが、 SQLインジェクションから安全です-ES2015構文では:

import {sql} from 'cool-sql-library'

let result = sql`select *
    from users
    where user_id = ${user_id}
      and password_hash = ${password_hash}`.execute()

console.log(result)

1
「エンコーディングを正しく行うのは難しい」-ハハハ。そうではない。1、2日で、すべて文書化されます。私は何年も前にORMのためにエンコーダーを書きました(SQLサーバーにはパラメーターの制限があるため、1つのステートメントに5000から10000行を挿入するのは問題があるためです(15年前)。大きな問題であることは覚えていません。
トムトム

1
おそらくSQL Serverは十分に規則的であり、問​​題はありませんが、他のDBで問題が発生しました-文字エンコードの不一致、不明瞭な構成オプション、ロケール固有の日付と番号の問題などのコーナーケース。すべて解決可能ですが、少なくともDBの癖について大雑把に理解する必要があります(MySQLとOracleを見ています)。
James_pic

3
@TomTomエンコーディングは、時間を考慮して実際に取得するのは非常に困難です。DBベンダーが次のリリースで新しいコメントスタイルを作成することを決定した場合、またはアップグレードでベアワードが新しいキーワードになった場合はどうしますか?理論的には、RDBMSの1つのリリースで実際にエンコードを取得し、次のリビジョンで間違っている可能性があります。でも持っているものにあなたがベンダーを切り替えるときに何が起こるかを始めるしない非標準の構文を使用して、条件付きコメントを
エリック

@エリック、それは率直に恐ろしいです。(私はPostgresを使用しています。そのような奇妙ないぼがある場合、私はまだそれらに遭遇していません。)
ワイルドカード

0

オプション1では、非常に大きな出力サイズにマップしようとしているsize = infinityの入力セットを使用しています。オプション2では、入力を選択したものに制限しました。言い換えると:

  1. [ すべての安全なSQLクエリ ] に対する慎重なスクリーニングとフィルタリング[ 無限大 ]
  2. 使用する[ 対象範囲に限定された事前に考慮されたシナリオ ]

他の回答によると、範囲を無限から管理しやすいものに制限することで、パフォーマンス上の利点も得られるようです。


0

SQL(特に現代的な方言)の有用なメンタルモデルの1つは、各SQLステートメントまたはクエリがプログラムであることです。ネイティブバイナリ実行可能プログラムでは、最も危険な種類のセキュリティ脆弱性はオーバーフローであり、攻撃者は異なる命令でプログラムコードを上書きまたは変更できます。

SQLインジェクションの脆弱性は、Cなどの言語のバッファオーバーフローと同型です。歴史から、バッファオーバーフローの防止は非常に困難であることが示されています。

オーバーフローの脆弱性を解決するための最新のアプローチの重要な側面の1つは、ハードウェアとOSメカニズムを使用して、メモリの特定の部分を非実行可能としてマークし、メモリの他の部分を読み取り専用としてマークすることです。(例えば、実行可能スペース保護に関するWikipediaの記事を参照してください。)そのようにして、攻撃者がデータを変更できたとしても、攻撃者は注入されたデータをコードとして扱うことはできません。

SQLインジェクションの脆弱性がバッファオーバーフローに相当する場合、NXビットまたは読み取り専用メモリページに相当するSQLは何ですか?答えは次のとおりです。準備されたステートメントには、パラメーター化されたクエリと、クエリ以外のリクエストに対する同様のメカニズムが含まれます。準備済みステートメントは読み取り専用とマークされた特定の部分でコンパイルされているため、攻撃者はプログラムのこれらの部分、および実行不能データ(準備済みステートメントのパラメーター)としてマークされた他の部分を変更できません。プログラムコードとして扱われることはないため、悪用の可能性のほとんどが排除されます。

確かに、ユーザー入力をサニタイズすることは良いことですが、本当に安全であるためには、妄想的である必要があります(または、同様に、攻撃者のように考える必要があります)。プログラムテキストの外側のコントロールサーフェスはそれを行う方法であり、準備されたステートメントはそのコントロールサーフェスをSQLに提供します。したがって、準備されたステートメント、したがってパラメーター化されたクエリが、セキュリティ専門家の大多数が推奨するアプローチであることは驚くことではありません。


これはすてきでダンディですが、タイトルごとの質問にはまったく対応していません。
-TomTom

1
@TomTom:どういう意味ですか?質問は、パラメーター化されたクエリがSQLインジェクションを防ぐための好ましいメカニズムである理由です。私の答えは、パラメーター化されたクエリがユーザー入力のサニタイズよりも安全で堅牢な理由を説明しています。
ダニエルプライデン

申し訳ありませんが、私の質問は「SQLインジェクション防止メカニズムがパラメーター化されたクエリを使用する方向に進化したのはなぜですか?」です。彼らはしませんでした。今についてではなく、歴史についてです。
トムトム

0

私はこのことについてここに書いています:https ://stackoverflow.com/questions/6786034/can-parameterized-statement-stop-all-sql-injection/33033576#33033576

しかし、単純にするために:

パラメータ化されたクエリが機能する方法は、sqlQueryがクエリとして送信され、データベースがこのクエリの処理内容を正確に認識し、その値が設定された場合のみユーザー名とパスワードを値として挿入することです。これは、データベースがクエリの処理内容をすでに知っているため、クエリに影響を与えることができないことを意味します。そのため、この場合、「Nobody OR 1 = 1 '-」のユーザー名と空のパスワードを検索しますが、これは間違っているはずです。

ただし、これは完全なソリューションではなく、入力検証を行う必要があります。これは、Javascriptをデータベースに入れることができるため、XSS攻撃などの他の問題には影響しないためです。次に、これがページに読み込まれると、出力検証に応じて、通常のjavascriptとして表示されます。そのため、実際に行うのに最適なのは入力検証を使用することですが、パラメーター化されたクエリまたはストアドプロシージャを使用してSQL攻撃を阻止します


0

SQLを使用したことはありません。しかし、明らかに、人々が抱えている問題について耳にし、SQL開発者はこの「SQLインジェクション」の問題を抱えていました。長い間、私はそれを理解できませんでした。そして、ユーザーが入力した文字列を連結することによって、SQLステートメント、実際のテキストSQLソースステートメントを作成する人々に気付きました。そして、その実現に関する私の最初の考えは衝撃でした。トータルショック。どうしてこんなにばかげてばかげて、そのようなプログラミング言語で文を作成できるのでしょうか?C、C ++、Java、Swiftの開発者にとって、これはまったくの狂気です。

ただし、C文字列を引数として取り、同じ文字列を表すCソースコードの文字列リテラルとまったく同じように見える別の文字列を生成するC関数を記述することはそれほど難しくありません。たとえば、その関数はabcを "abc"に、 "abc"を "\" abc \ ""に、 "\" abc \ ""を "\" \\ "abc \\" \ ""に変換します。(まあ、これがあなたに間違っているようであれば、それはhtmlです。それを入力したときは正しいのですが、表示されるときではありません)そして、そのC関数が書かれれば、Cソースコードを生成することはまったく難しくありません。ユーザーが入力した入力フィールドのテキストは、C文字列リテラルに変換されます。安全にするのは難しくありません。SQL開発者がSQLインジェクションを回避する方法としてそのアプローチを使用しない理由は、私を超えています。

「サニタイズ」は完全に欠陥のあるアプローチです。致命的な欠陥は、特定のユーザー入力が違法になることです。汎用テキストフィールドに;などのテキストを含めることができないデータベースになります。テーブルをドロップするか、SQLインジェクションで使用して破損を引き起こすものは何でも。私はそれをまったく受け入れられないと思います。データベースにテキストを保存する場合、任意のテキストを保存できる必要があります。そして、実用的な欠陥は、サニタイザーがそれを正しくすることができないようであるということです:-(

もちろん、パラメーター化されたクエリは、コンパイルされた言語を使用するプログラマーが期待するものです。文字列の入力があり、それをSQL文字列に変換することはありませんが、パラメータとして渡すだけで、文字列内の文字が損傷を引き起こす可能性はありません。

コンパイルされた言語を使用する開発者の観点からすると、サニタイズは私には決して起こらないものです。サニタイズの必要性は非常識です。パラメータ化されたクエリは、問題の明らかな解決策です。

(Josipの答えは興味深いものでした。基本的に、パラメーター化されたクエリを使用すると、SQLに対する攻撃を阻止できますが、JavaScriptインジェクションの作成に使用するデータベースにテキストを含めることができます:-( 、Javascriptがそれに対する解決策を持っているかどうかはわかりません。


-2

主な問題は、パラメーター化されたクエリがパフォーマンスとメモリの追加の利点と完全に機能する既存の手順であったのに対し、ハッカーが衛生を取り囲む方法を見つけたことです。

「一重引用符と二重引用符だけ」として問題を単純化する人もいますが、ハッカーは異なるエンコーディングの使用やデータベース機能の使用など、検出を回避する賢明な方法を見つけました。

とにかく、壊滅的なデータ侵害を引き起こすには、1つの文字列を忘れるだけで済みました。スクリプトを自動化して、シリーズまたはクエリを含む完全なデータベースをダウンロードできるハッカー。ソフトウェアがオープンソーススイートや有名なビジネススイートのようによく知られている場合、ユーザーとパスワードの表を単純にアタッチできます。

一方、連結クエリを使用することは、使用方法を習得し、それに慣れるだけの問題でした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.