URL内のダブルエスケープシーケンス:リクエストフィルタリングモジュールは、ダブルエスケープシーケンスを含むリクエストを拒否するように構成されています


86

ASP.NET MVCアプリケーションで、次のようなURLを実装しようとしています。

/ product / tags / for + familys

デフォルト構成でアプリケーションを実行しようとすると、404.11応答コードで次のメッセージが表示されます。

HTTPエラー404.11-見つかりません

リクエストフィルタリングモジュールは、ダブルエスケープシーケンスを含むリクエストを拒否するように構成されています。

web.config内に以下のコードを実装することで、このエラーを回避できます。

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>

だから、今私は何も得ていません404.11

私が疑問に思っているのは、この実装でどのようなセキュリティホールを開いているのかということです。

ところで、私のアプリケーションはの下に.Net Framework 4.0あり、の下で実行されていIIS 7.5ます。


/product/tags/for%20families代わりにを使用して目的のリソースに到達することは可能ですか?次に、スペースを含むIDの回避策があります。それとも私は完全にここから離れていますか?
Anders Tornblad 2011年

@atornbladは少しずれていると思います。私の質問:私が疑問に思っているのは、この実装でどのようなセキュリティホールを開いているのかということです。
tugberk 2011年

回答:


57

開く可能性のあるセキュリティホールは、コードインジェクション(HTMLインジェクション、JavaScriptインジェクション、SQLインジェクション)に関係しています。

デフォルト設定では、一般的なインジェクション戦略が機能しないようにすることで、攻撃から半効率的に保護します。削除するデフォルトのセキュリティが多いほど、URL、GETリクエストクエリ文字列、POSTリクエストデータ、HTTPヘッダーなどを介して提供される入力をどのように処理するかについて考える必要があります...

たとえばid、アクションメソッドのパラメータに基づいて動的SQLクエリを作成する場合、次のようになります。

public ActionResult Tags(string id)
{
    var sql = "SELECT * FROM Tags Where tagName = '" + id + "'";
    // DO STUFF...
}

(...これは良い考えではありません)、. NET Frameworkによって設定されたデフォルトの保護は、ユーザーがこのURLを要求するなど、より危険なシナリオのいくつかを停止する可能性があります。

/product/tags/1%27;drop%20table%20Tags;%20--

全体的なアイデアは、URLのすべての部分およびアクションメソッドへの他の入力を潜在的な脅威として扱うことです。デフォルトのセキュリティ設定は、その保護の一部を提供します。変更する各デフォルトのセキュリティ設定は、手動で処理する必要があるもう少し潜在的な問題を引き起こします。

この方法でSQLクエリを作成していないと思います。しかし、ユーザー入力をデータベースに保存し、後でそれらを表示すると、より卑劣なものが発生します。悪意のあるユーザーは、JavaScriptまたはHTMLをデータベースに保存して、エンコードせずに送信する可能性があります。これにより、システムの他のユーザーが脅かされる可能性があります。


6

セキュリティリスク

この設定allowDoubleEscapingpath(cs-uri-stem)にのみ適用され、OWASP DoubleEncodingによって最もよく説明されます。この手法は、リクエストを2回URLエンコードすることでセキュリティ制御を回避するために使用されます。例としてURLを使用する:

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies

専用のセキュリティ制御があるとし/product/tags/for+familiesます。/product/tags/for%252Bfamilies前述のセキュリティ制御によってチェックされていないにもかかわらず、同じリソースである要求が到着します。認証されたユーザーの要求、SQLiのチェックなど、セキュリティ制御の一般的な用語を使用しました。

IISがブロックするのはなぜですか?

プラス記号(+)は、RFC2396で予約されている文字です。

多くのURIには、特定の特殊文字で構成される、またはそれによって区切られるコンポーネントが含まれています。これらの文字は、URIコンポーネント内での使用が予約された目的に制限されているため、「予約済み」と呼ばれます。URIコンポーネントのデータが予約された目的と競合する場合は、URIを形成する前に、競合するデータをエスケープする必要があります。

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

Wade Hilmoには、IISがURL内の文字をブロックする方法というタイトルの優れた投稿があります。提供される情報と背景はたくさんあります。プラス記号専用の部分は次のとおりです。

したがって、allowDoubleEscaping / VerifyNormalizationは非常に簡単に思えます。なぜ混乱を招くと言ったのですか?問題は、「+」文字がURLに表示される場合です。'+'文字は '%'を含まないため、エスケープされていないように見えます。また、RFC 2396は、エスケープされた形式(%2b)の場合にURLに含めることができる予約文字としてそれを示しています。ただし、allowDoubleEscapingをデフォルト値のfalseに設定すると、エスケープされた形式でもブロックされます。この理由は歴史的です。HTTPの初期の頃、「+」文字はスペース文字の省略形と見なされていました。一部のcanonicalizerは、「+」を含むURLを指定すると、それをスペースに変換します。このため、URLでは「+」は非正規であると見なされます。この「+」処理を呼び出すRFCへの参照を見つけることができませんでした。

私自身の経験から、IISログを記録すると、要求スペースがプラス記号に置き換えられることがわかります。名前にプラス記号を付けると、ログを解析するときに混乱が生じる可能性があります。

解決

これを修正する方法は3つあり、プラス記号を使用する方法は2つあります。

  1. allowDoubleEscaping=true-これにより、Webサイト/アプリケーション全体を二重にエスケープできます。内容によっては、控えめに言っても望ましくない場合があります。次のコマンドはを設定しallowDoubleEscaping=trueます。

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls-リクエストフィルタリングは、ホワイトリストアプローチを提供します。そのURLパスをalwaysAllowedUrlsに追加することにより、要求は他の要求フィルタリング設定によってチェックされず、IIS要求パイプラインで続行されます。ここでの懸念は、リクエストフィルタリングが次のリクエストをチェックしないことです。

    • リクエストの制限:maxContentLength、maxUrl、maxQueryString
    • 動詞
    • クエリ-クエリ文字列パラメータはチェックされません
    • ダブルエスケープ
    • 高ビット文字
    • フィルタリングルールのリクエスト
    • リクエストヘッダーの制限

    次のコマンドは、デフォルトのWebサイトに追加/product/tags/for+familiesalwaysAllowedUrlsれます。

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. 名前の変更-はい、ファイル/フォルダー/コントローラーなどの名前を変更するだけです。可能なら。これが最も簡単な解決策です。


:IIS Expressは、ここで私がやったことだと、開発中のallowDoubleEscapingにstackoverflow.com/q/56463044/381082
DeveloperDan

5

私はこれを回避するための作業を行いました。したがって、(IIS)のURL内に文字列を挿入する場合は、ダーティからクリーンアップする必要があります:{";"、 "/"、 "?"、 ":"、 "@"、 "&"、 " = "、" + "、" $ "、"、 "}; そして、それを解読して再び使用したいときは、それを解読する前に(望ましい結果を得るために)再び汚れさせる必要があります。

これが私のコードです、私はそれが誰かを助けることを願っています:

 public static string cleanUpEncription(string encriptedstring)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m","s1l2a3s4h","q1e2st3i4o5n" ,"T22p14nt2s", "a9t" , "a2n3nd","e1q2ua88l","p22l33u1ws","d0l1ar5","c0m8a1a"};

            foreach (string dirtyCharacter in dirtyCharacters)
            {
                encriptedstring=encriptedstring.Replace(dirtyCharacter, cleanCharacters[Array.IndexOf(dirtyCharacters, dirtyCharacter)]);
            }
            return encriptedstring;
        }

        public static string MakeItDirtyAgain(string encriptedString)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m", "s1l2a3s4h", "q1e2st3i4o5n", "T22p14nt2s", "a9t", "a2n3nd", "e1q2ua88l", "p22l33u1ws", "d0l1ar5", "c0m8a1a" };
            foreach (string symbol in cleanCharacters)
            {
                encriptedString = encriptedString.Replace(symbol, dirtyCharacters[Array.IndexOf(cleanCharacters,symbol)]);
            }
            return encriptedString;
        }

pntGlmとは何ですか?
StuperUser

@StuperUserはランダムな文字だけ
MarkDibeh19年

1
文字列は base64この置換手法を使用する代わりに、エンコードする。たとえば、基本認証ではbase64、送信された資格情報に特殊/予約文字が含まれている可能性があるため、これを使用してエンコードします。
user23204 6420年

base64の問題は/ base64文字であり、ルートを壊す可能性があります
GarrGodfrey20年

1

そのため、MVCアプリからAPIを呼び出していたときに、これに遭遇しました。セキュリティホールを開く代わりに、パスを変更しました。

まず、この設定を無効にしないことをお勧めします。アプリケーション/リソースの設計を変更する方が適切です(たとえば、パスをエンコードする、ヘッダーまたは本文でデータを渡す)。

これは古い投稿ですが、System.WebのHttpUtility.UrlPathEncodeメソッドを使用してAPIの呼び出しからこれを受け取った場合に、このエラーを解決する方法を共有したいと思いました。

私は呼び出しを行うためにRestSharpを使用しているので、私の例はRestRequestを使用しています。

var tags = new[] { "for", "family" };
var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}");

これにより、次のパスが生成されます。

/ product / tags / for%2Bfamilies

別の注意点として、ユーザーの入力に基づいて動的クエリを作成しないでください。常にSqlParameterを使用する必要があります。また、セキュリティの観点から、インジェクション攻撃を防ぐために適切なエンコーディングで値を返すことが非常に重要です。

〜乾杯


0

分離された暗号化された文字列をエンコードします。

return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes("string"));

分離された暗号化された文字列をデコードします。

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