web-dev-qa-db-ja.com

SQLインジェクション-エスケープ引用符が安全ではなくなったのはなぜですか?

生のSQL

SQLを作成しているとき、実際に人間の入力を必要とするものについては、インジェクションを回避するために多くのことが行われています。

SQLインジェクションを聞いた人なら誰でも知っています(私はPHPを使用します)このようなことをするのは安全ではありません:

_$sql = "SELECT * FROM `users` 
.  WHERE `userName` = "{$_POST["username"]}" 
.  AND `pass` = "{$_POST["pass"]}";";
_

マジック

もちろん、誰かが「マジックエスケープクォート」を使用して、適切にサニタイズされなかったプログラム入力を処理し、悪い習慣の結果としてSQLに直接入力するというアイデアを思いついた人もいます。これはSQLインジェクションの問題を実際に解決しませんでしたが、すべてのユーザー入力が混乱したことを意味しました。

スラッシュを追加する

だから、一部の人々は魔法の引用符をオフにしました。次に、SQLの前にaddslashes()を介してユーザー入力を解析しました。これにより、理論的にはすべての引用符がエスケープされ、ハッカーは_' OR 1=1_を実行できませんが、addslashesのドキュメントでさえ、追加スラッシュは使用しないでください。mysql_real_escape_string()などのデータベース固有の関数を使用するように記載されていますが、これでもまだ十分ではないと言われています。

データベース固有のスラッシュを追加する

したがって、DBMS固有の_*_real_escape_string_を使用することはできません。_add slashes_を使用することもできません。

「専用のハッカーは、引用エスケープループをジャンプする方法を見つけます。DBALの準備済みステートメントを使用するだけです」-John Q任意のプログラマー

さて、それで、準備ステートメントとDBALを使用するのに十分怖くなりました。それは実際には何も説明しませんでしたが、私はそれをたくさん聞いたのでそれはいいですね。

準備されたステートメント

したがって、PDO、またはフレームワークのDBAL、またはすべてのSQLをラップし、誰かがSQLインジェクションを実行できないようにする他の何かを使用しています。

私の質問は、基本的には「どうして?」ではなく、「何を使うべきか」ではありません。これを使用するか、それともwhatを使用するように指示する人でいっぱいのウェブですが、これらのことが起こる必要があった理由の説明はありません。

直接的な質問

指摘された質問(リマインダー、私はSQLについて尋ねています、PHPはSQLの周りの悪い担当者のためにサンプル言語でした、概念は普遍的です):

  1. 「マジック」を使用してすべてのユーザー入力をエスケープできないのはなぜですか?
  2. Addlashesが「十分」に機能しなかったのはなぜですか?
  3. DB固有のエスケープ関数の使用の何が問題になっていますか。
  4. フレームワークとPDOを備えた準備済みステートメントがSQLのゴールドスタンダードとして認められているのはなぜですか?なぜ彼らはより良いのですか?これらでSQLインジェクションを実行できないのはなぜですか?プログラマーはどういうわけかまだこれを台無しにすることができませんか?彼らは何に注意すべきですか?
  5. 私が取り上げていない他の懸念事項はありますか?
78
Incognito

「マジック」を使用してすべてのユーザー入力をエスケープできないのはなぜですか?

マジックが適用された時点では、データがどこに到達するかは不明です。したがって、魔法の引用はデータを破壊しています。ただし、データベースにエスケープせずに書き込まれる場合を除きます。

これは、クライアントに送り返されるHTML応答でのみ使用できます。完全に入力されていないため、ユーザーに再度表示されるフォームを考えてみてください。マジッククオートにより、最初の試行で入力されたデータはSQLエスケープされます。これはHTMLページでは意味がありません。さらに悪いことに、2番目の送信では、データは再びSQLエスケープされます。

Addlashesが「十分」に機能しなかったのはなぜですか?

マルチバイト文字に関する問題があります。

' 27
\ 5c
뼧 bf 5c

これらは2バイトですが、Unicode文字は1つだけです。

addslashesはUnicodeについて何も知らないため、入力bf 27bf 5c 27に変換します。これがユニコード対応プログラムによって読み取られる場合、뼧 'と見なされます。ブーム。

http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string に、この問題の適切な説明があります。

DB固有のエスケープ関数の使用の何が問題になっていますか。

それらは、エスケープがデータベースが行うのと同じ方法でデータを解釈することを保証するため、優れています(最後の質問を参照)。

セキュリティの観点からは、すべてのデータベース入力に使用しても問題ありません。しかし、彼らはあなたがどこかでそれらのいずれかを忘れてしまうリスクを持っています。

Edit:getahobbyが追加したとおり:または、SQLステートメントで引用符を追加せずに、数値によるxxx_escape_stringsを使用して、実際の数値であることを確認せずに入力を適切なデータ型にキャストまたは変換する/ Edit

ソフトウェア開発の観点からすると、他のSQLデータベースサーバーソフトウェアのサポートを追加するのが非常に困難になるため、問題が発生します。

フレームワークとPDOを備えた準備済みステートメントがSQLのゴールドスタンダードとして認められているのはなぜですか?なぜ彼らはより良いのですか?

ソフトウェアの設計上の理由から、PDOはほとんどが良いことです。これにより、他のデータベースサーバーソフトウェアのサポートが非常に簡単になります。オブジェクト固有のインターフェイスを備えており、データベース固有の非互換性の多くを抽象化しています。

これらの[準備されたステートメント]を使用してSQLインジェクションを実行できないのはなぜですか。

ここで重要なのは、準備済みステートメントの「可変パラメーターを使用した定数クエリ」の部分です。データベースドライバーは、開発者が考える必要なく、すべてのパラメーターを自動的にエスケープします。

パラメーター化されたクエリは、構文上の理由から、エスケープされたパラメーターを使用した通常のクエリよりも読みやすいことがよくあります。環境によっては、少し速くなる場合があります。

常にパラメーター付きの準備済みステートメントを使用することは、静的コード分析ツールで検証できるものです。 xxx_escape_stringへの欠落した呼び出しは、簡単かつ確実に発見されません。

プログラマはどうにかしてこれを台無しにできないのでしょうか?彼らは何に注意すべきですか?

「準備されたステートメント」は、constantであることを意味します。特にユーザー入力を使用して、準備されたステートメントを動的に生成する場合でも、すべての注入の問題があります。

52

[1.]「マジック」を使用してすべてのユーザー入力をエスケープできないのはなぜですか?

マジッククオートは2つの点で壊れているので:

  1. すべての$ _(REQUEST/GET/POST)データがDBに入るわけではありません。そして、それを理解するには、入力をエスケープする必要があります。
  2. これらはaddslashesと同等です([2.]の私のメモを参照)。したがって、実際には安全ではありません。

[2.]つけまつげが「十分」に機能しなかったのはなぜですか?

addslashesの制限を回避するには多くの方法があります。そのため、根本的に欠陥がありますが、それを使用しようとします。

[3.] DB固有のエスケープ関数を使用することの何が問題になっていますか。

本当に何もない。それが、PDO/Preparedの方が「優れている」理由の説明です。エンコーディングを含む多くの要素を処理するので、それらはwayaddslashesより優れています。 ここに少し秘密があります。PDOは内部的にそれらを使用しますが、addslashes...は使用しません

[4.]フレームワークとPDOを備えた準備済みステートメントがSQLのゴールドスタンダードとして認められているのはなぜですか?なぜ彼らはより良いのですか?これらでSQLインジェクションを実行できないのはなぜですか?

それらはゴールドスタンダードではないであり、「より安全」ではない DB固有の関数よりも--SQLインジェクションが可能同様に。いいえ、適切にサニタイズされた入力でSQLインジェクションを行うことはできません。

そこにあるすべてのテクノロジーと同様に、開発者は何か「新しい」ものに対して宗教的(狂信的)な傾向を発達させる傾向があります。そのため、ベテランのZend Certified Engineers(TM)に、準備済みのステートメントに切り替えることを強制することなく、アドバイスを受けます。

ただし、実際には、何をしているのかを知ることがすべてにかかっています。記事を数値IDでロードする場合は、PDOを使用することなく、エスケープを行う必要はありません。 IDが整数であることを確認する必要があるだけです。

より現実的な観点から、一般的なルールはPDO /準備されたステートメントを使用するのではなく、正しい関数を使用することです。つまり、あなたはmustmysql_real_escape_string()ではなくaddslashes()を使用します] _またはmysql_escape_string()

[5.]プログラマはどうにかしてこれを台無しにすることができませんか?彼らは何に注意すべきですか?

もちろん!しかし、それは「注意すべきこと」ではなく、「何をしているのかを知る」ことです。

ご覧のとおり、eval($_GET['code']) *は、適切な場所(ローカルPHP Test Runnerなど)で使用すると完全に合法になります。

ORMを使用して条件付きクエリを実行する場合、コードを直接入力しているため、正しく実行しないとSQLインジェクションが発生する可能性があります(問題のORMによって異なります)。 (仮定)例:

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(*私は無数の専門家がこれに頭をぶつけているとしか想像できません)

13
Christian

1日の終わりに、SQLインジェクションからクエリを保護するために、入力のエスケープを行う必要があります。 PDOやADODBなどのパラメーター化されたクエリライブラリは、エスケープを使用します。これらは、暗黙的に安全な方法でこのプラクティスを強制するだけです。 magic_quotes_gpcは[〜#〜]しない[〜#〜]とは対照的に、これは根本的に問題のあるアプローチです。

1)何をしているか理解していない場合、エスケープは問題になる可能性があります。このタイプの問題は、magic_quotes_gpcが有効になっている場合でも悪用可能です。

mysql_query("select * from users where id=".addslashes($_GET[id]));

PoCエクスプロイト: http://localhost/vuln.php?id = sleep(

patch:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

レッスン:SQLインジェクションを利用するために引用符は必要ありません。

2)引用符のみをエスケープするとします。

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

PoC Exploit: http://localhost/vuln.php?name = \&id = + or + sleep(30)/ *

パッチ:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

レッスン:バックスラッシュは引用符と同じように危険です。

3)言語エンコードについてはどうですか?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

PoC Exploit:http://localhost/vuln.php?name =%bf%27 = sleep(30)/ *

パッチ:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

結論:

アプリケーションでのSQLインジェクションを防ぐために、エスケープは絶対に必要です。 PHP PDOとADOBは、パラメータ化されたクエリライブラリであり、ユーザー入力のエスケープを強制します。問題は、多くのプログラマがエスケープとは何かを理解していないことです。このセキュリティポリシーを強制するライブラリを用意することは、エスケープルールを理解する必要がないため、最善の防御方法です。

9
rook

DB固有のエスケープ関数について。 mysql_real_escape_string()が使用されている場合でも、SQLインジェクションが発生するシナリオは多数あります。 LIMITとORDER BYは本当にトリッキーです!

これらの例はSQLインジェクションに対して脆弱です:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
$sql = "SELECT userid, username FROM sql_injection_test LIMIT $offset, 10";

または

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
$sql = "SELECT userid, username FROM sql_injection_test ORDER BY `$order`";

どちらの場合も、 'を使用してカプセル化を保護することはできません。

source :予期しないSQLインジェクション(エスケープが十分でない場合)<-これを読む

5
Cut Copy

フィルターをバイパスすることができ、SQLステートメントに入るデータは、ユーザー入力以外の場所からも取得できます。 1つの例として、SQLの影響を受けるソース/シンクへのエントリポイントを格納(高次)できますが、HTTP GETパラメータとPOST HTMLフォームのパラメータは、ユーザーの唯一の方法ではありません入力。

パラメータ化されたクエリは、SQLステートメントをインジェクションから解放する必要はありません。また、変数のバインド、文字列操作/連結の削除、広範囲のSQL句による特定のセキュリティ問題の回避も必要です。

ほとんどの開発者は、SQLインジェクションの問題についてサードパーティのコンポーネントやその他の依存関係を確認することを忘れており、これらのインクルードによって独自のコードが脆弱になる可能性があることに気付かない場合があります。

最善の方法は、アプリケーションセキュリティコンサルティング会社を雇って、本番環境での準備のためにアプリケーションを準備し、アプリケーションセキュリティコントロールをプロセスと開発テクノロジに組み込むことについてappdevチームをトレーニングすることです。

4
atdre

ヘンドリックの答えを拡張する。 real_escape_stringは、実際にはそうでない場合でも魔法の弾丸と考えるのは簡単です。代わりにintvalを使用したり、入力を整数にキャストしたりするときに、この関数を使用する人を見てきました。エスケープ文字列を間違ったコンテキストで使用すると、注入される可能性があります。

3
getahobby