web-dev-qa-db-ja.com

url内の二重エスケープシーケンス:要求フィルタリングモジュールは、二重エスケープシーケンスを含む要求を拒否するように構成されています

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

/ product/tags/for + families

デフォルト設定でアプリケーションを実行しようとすると、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の下で実行されています。

78
tugberk

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

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

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

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

(...[〜#〜] not [〜#〜]は良いアイデアです)、. NETフレームワークによって設定されたデフォルトの保護は、いくつかのより危険なシナリオを停止する可能性があります、このURLをリクエストするユーザーのように:

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

全体的な考えは、URLのすべての部分とアクションメソッドへの他の入力を潜在的な脅威として扱うことです。デフォルトのセキュリティ設定は、その保護の一部を提供します。変更するデフォルトのセキュリティ設定はそれぞれ、手動で処理する必要があるもう少し潜在的な悪用になります。

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

51
Anders Tornblad

セキュリティリスク

allowDoubleEscapingの設定はpath(cs-uri-stem)にのみ適用され、 OWASP Double Encoding で最もよく説明されます。この手法は、リクエストを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 Block?

プラス記号(+)は、 RFC2396 ごとの予約文字です。

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

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

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

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

私自身の経験から、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サイトのalwaysAllowedUrls/product/tags/for+familiesを追加します。

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

2
user2320464

私はこれのための仕事をしました。したがって、暗号化された文字列を(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;
        }
1
mark dibe

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

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

これは古い投稿ですが、 HttpUtility.UrlPathEncodeSystem.Web のメソッド。

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

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

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

/ product/tags/for%2Bfamilies

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

〜乾杯

0
Rogala