78

これを開始するには、パラメーター化されたクエリが最適なオプションであることをよく知っていますが、以下に提示する戦略が脆弱になる理由を尋ねています. 以下の解決策はうまくいかないと人々は主張しているので、うまくいかない理由の例を探しています。

動的 SQL が、SQL Server に送信される前に次のエスケープを使用してコードに組み込まれている場合、これを無効にできるのはどのような種類のインジェクションですか?

string userInput= "N'" + userInput.Replace("'", "''") + "'"

同様の質問がここで回答されましたが、ここで該当する回答はないと思います。

SQL Server では、単一引用符を "\" でエスケープすることはできません。

生成される文字列が単一引用符の前にある N によって Unicode としてマークされているという事実によって、 Unicode を使用したSQL スマグリング(ここで概説) が阻止されると思います。私の知る限り、SQL Server が自動的に単一引用符に変換する文字セットは他にありません。エスケープされていない一重引用符がなければ、インジェクションは不可能だと思います。

String Truncationも実行可能なベクトルだとは思いません。microsoft によるとnvarchar、 の最大サイズは 2GBであるため、SQL Server は確かに切り捨てを行いません。ほとんどの場合、2 GB の文字列は実行不可能であり、私の場合も不可能です。

二次注入は可能ですが、次の場合は可能ですか:

  1. データベースに入るすべてのデータは、上記の方法を使用してサニタイズされます
  2. データベースからの値が動的 SQL に追加されることはありません (動的 SQL 文字列の静的部分でテーブル値を参照できるのに、なぜそんなことをするのでしょうか?)。

これがパラメーター化されたクエリを使用するよりも優れている、またはその代替手段であると示唆しているわけではありませんが、概説したものがどのように脆弱であるかを知りたい. 何か案は?

4

6 に答える 6

48

このエスケープ関数が失敗する場合がいくつかあります。最も明白なのは、一重引用符が使用されていない場合です。

string table= "\"" + table.Replace("'", "''") + "\""
string var= "`" + var.Replace("'", "''") + "`"
string index= " " + index.Replace("'", "''") + " "
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index

この場合、二重引用符、バックティックを使用して「ブレイクアウト」できます。最後のケースでは、「ブレイクアウト」するものは何もないため1 union select password from users--、攻撃者が望む SQL ペイロードを書き込むだけでかまいません。

このエスケープ関数が失敗する次の条件は、文字列がエスケープされた後に部分文字列が取得された場合です (そして、私はこのような脆弱性を実際に発見しました) :

string userPassword= userPassword.Replace("'", "''")
string userName= userInput.Replace("'", "''")
userName = substr(userName,0,10)
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'";

この場合、ユーザー名 はエスケープ関数によって変換され、部分文字列を取得することによって に戻されabcdefgji'ます。これは、パスワード値を任意の sql ステートメントに設定することで悪用される可能性があります。この場合、パスワードはsql として解釈され、ユーザー名は として解釈されます。結果のクエリは次のとおりです。abcdefgji''abcdefgji'or 1=1--abcdefgji'' and password=

select * from users where name='abcdefgji'' and password=' or 1=1-- 

T-SQL およびその他の高度な SQL インジェクション手法については、既に言及されています。Advanced SQL Injection In SQL Server Applicationsは優れた論文であり、まだ読んでいない場合は読む必要があります。

最後の問題はユニコード攻撃です。このクラスの脆弱性は、エスケープ機能がマルチバイト エンコーディングを認識しないために発生し、攻撃者がこれを使用してエスケープ文字を「消費」する可能性があります。文字列の先頭に「N」を追加しても、文字列の後半にあるマルチバイト文字の値には影響しないため、役に立ちません。ただし、このタイプの攻撃は非常にまれです。なぜなら、データベースは GBK Unicode 文字列を受け入れるように構成する必要があるからです (MS-SQL でこれができるかどうかはわかりません)。

二次コード インジェクションは引き続き可能です。この攻撃パターンは、攻撃者が制御するデータ ソースを信頼することによって作成されます。エスケープは、制御文字を文字リテラルとして表すために使用されます。開発者が a から取得した値をエスケープするのを忘れ、selectこの値を別のクエリで使用すると、攻撃者は文字リテラルの一重引用符を自由に使用できます。

すべてをテストし、何も信用しません。

于 2013-03-24T07:52:01.467 に答える
19

いくつかの追加の規定により、上記のアプローチは SQL インジェクションに対して脆弱ではありません。考慮すべき攻撃の主なベクトルは、SQL スマグリングです。SQL Smuggling は、類似の Unicode 文字が予期しない方法で変換された場合に発生します (たとえば、「 に変更」)。アプリケーション スタックが SQL スマグリングに対して脆弱な場所がいくつかあります。

  • プログラミング言語は Unicode 文字列を適切に処理しますか? 言語が Unicode に対応していない場合、Unicode 文字のバイトを単一引用符と誤認してエスケープする可能性があります。

  • クライアント データベース ライブラリ (ODBC など) は、Unicode 文字列を適切に処理しますか? .Net フレームワークの System.Data.SqlClient はそうですが、Windows 95 時代の古いライブラリはどうでしょうか。サードパーティの ODBC ライブラリは実際に存在します。ODBC ドライバーがクエリ文字列で Unicode をサポートしていない場合はどうなりますか?

  • DB は入力を正しく処理しますか? SQL の最新バージョンは、N を使用していると仮定して免疫がありますが、SQL 6.5 はどうでしょうか? SQL7.0? 私は特定の脆弱性を認識していませんが、これは 1990 年代の開発者には注目されていませんでした。

  • バッファオーバーフロー?もう 1 つの問題は、引用符で囲まれた文字列が元の文字列よりも長いことです。入力の 2 GB 制限が導入された Sql Server のバージョンはどれですか? その前に限界は?古いバージョンの SQL では、クエリが制限を超えるとどうなりますか? ネットワーク ライブラリの観点から、クエリの長​​さに制限はありますか? それとも、プログラミング言語の文字列の長さですか?

  • Replace() 関数で使用される比較に影響する言語設定はありますか? .Net は常に Replace() 関数のバイナリ比較を行います。いつもそうなのだろうか?.NET の将来のバージョンが app.config レベルでの動作のオーバーライドをサポートするとどうなりますか? 一重引用符を挿入するために Replace() の代わりに正規表現を使用するとどうなるでしょうか? コンピュータのロケール設定はこの比較に影響しますか? 動作の変更が発生した場合、SQL インジェクションに対して脆弱ではない可能性がありますが、DB に到達する前に、一重引用符のように見える Uni-code 文字を一重引用符に変更して、文字列を誤って編集した可能性があります。

したがって、SQL サーバーの現在の (2005-2012) バージョンに対して組み込みの SqlClient ライブラリを使用して、現在のバージョンの .Net で C# の System.String.Replace() 関数を使用していると仮定すると、あなたのアプローチはそうではありません。脆弱。物事を変え始めると、約束はできなくなります。パラメーター化されたクエリのアプローチは、効率、パフォーマンス、および (場合によっては) セキュリティの点で正しいアプローチです。

警告上記のコメントは、この手法を推奨するものではありません。これが SQL を生成するための間違ったアプローチである理由は他にもいくつかあります。ただし、それらの詳細は、この質問の範囲外です。

この手法を新しい開発に使用しないでください。

この手法を新しい開発に使用しないでください。

この手法を新しい開発に使用しないでください。

于 2013-03-29T19:18:47.213 に答える
8

クエリ パラメーターを使用する方が、引用符をエスケープするよりも優れており、簡単で高速です。


あなたのコメントについては、パラメーター化を認めたようですが、強調する価値があります。パラメータ化できるのに、なぜエスケープを使用したいのでしょうか?

Advanced SQL Injection In SQL Server Applicationsで、テキスト内の「置換」という単語を検索し、その時点から、開発者がユーザー入力をエスケープした後でも SQL インジェクション攻撃をうっかり許可してしまった例をいくつか読んでください。


一部の文字セットでは有効なマルチバイト文字の半分になる\ため、引用符をエスケープすると脆弱性が発生するエッジ ケースがあります。ただし、エスケープ文字ではないため、\これはあなたのケースには当てはまりません。\

他の人が指摘しているように、文字列リテラルまたは日付リテラル以外の動的コンテンツを SQL に追加している可能性もあります。"テーブルまたは列の識別子は、SQL または[ ]Microsoft/Sybaseでは で区切られます。もちろん、SQL キーワードには区切り文字がありません。これらのケースでは、補間する値をホワイトリストに登録することをお勧めします。

肝心なのは、一貫して確実に回避できるのであれば、回避は効果的な防御であるということです。これがリスクです。アプリケーションの開発者チームの 1 人が手順を省略し、安全でない文字列補間を行う可能性があります。

もちろん、パラメータ化などの他の方法についても同じことが言えます。一貫して行う場合にのみ効果があります。しかし、適切なタイプのエスケープを理解するよりも、パラメーターを使用する方が簡単で速いことがわかりました。開発者は、便利で速度を落とさない方法を使用する可能性が高くなります。

于 2013-03-21T00:50:55.560 に答える
4

ユーザーが提供した入力がコマンドとして解釈されると、SQL インジェクションが発生します。ここでコマンドとは、認識されたデータ型リテラルとして解釈されないものを意味します。

ユーザーの入力をデータ リテラル、具体的には文字列リテラルのみで使用している場合、ユーザー入力は、文字列リテラルのコンテキストを離れることができる場合にのみ、文字列データとは異なるものとして解釈されます。文字列または Unicode 文字列リテラルの場合、リテラル データを囲むのは一重引用符ですが、埋め込まれた一重引用符は 2 つの一重引用符で表す必要があります。

したがって、文字列リテラル コンテキストを終了するには、単一引用符 (sic) を指定する必要があります。これは、2 つの単一引用符が、文字列リテラルの終了区切り文字としてではなく、文字列リテラル データとして解釈されるためです。

したがって、ユーザーが提供したデータ内の単一引用符を 2 つの単一引用符で置き換える場合、ユーザーは文字列リテラル コンテキストを離れることができなくなります。

于 2013-03-21T06:27:00.827 に答える
1

文字列の連結を行っている場合、おそらく 100% 安全な方法はありません。できることは、各パラメーターのデータ型をチェックして、すべてのパラメーターがそのような検証に合格した場合に実行を進めることです。たとえば、パラメーターが int 型である必要があり、int に変換できないものを取得している場合は、それを拒否してください。

ただし、nvarchar パラメーターを受け入れている場合、これは機能しません。

他の人がすでに指摘したように。最も安全な方法は、パラメーター化されたクエリを使用することです。

于 2013-03-21T10:14:47.003 に答える