podwójna sekwencja ucieczki w adresie URL: moduł filtrowania żądań jest skonfigurowany tak, aby odrzucać żądanie zawierające podwójną sekwencję ucieczki

86

W mojej aplikacji ASP.NET MVC próbuję zaimplementować adres URL, jak poniżej:

/ produkt / tagi / dla + rodzin

Kiedy próbuję uruchomić aplikację z domyślnymi konfiguracjami, otrzymuję ten komunikat z kodem odpowiedzi 404.11:

Błąd HTTP 404.11 - Nie znaleziono

Moduł filtrowania żądań jest skonfigurowany tak, aby odrzucać żądanie zawierające podwójną sekwencję ucieczki.

Mogę obejść ten błąd, implementując poniższy kod w moim web.config:

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

Więc teraz nie dostaję żadnego 404.11.

Zastanawiam się, jakie rodzaje luk w zabezpieczeniach otwieram w tej implementacji.

A tak przy okazji, moja aplikacja jest .Net Framework 4.0uruchomiona i działa pod IIS 7.5.

tugberk
źródło
Czy można /product/tags/for%20familieszamiast tego dotrzeć do żądanego zasobu ? Następnie masz obejście dla identyfikatorów zawierających spacje. A może jestem tutaj całkowicie wyłączony?
Anders Tornblad
@atornblad trochę off chyba. Moje pytanie: Zastanawiam się, jakie luki w zabezpieczeniach otwieram w tej implementacji.
tugberk
5
IIS rzuca znak „+”, co jest domyślnym zachowaniem firmy Microsoft.
Todd Shelton,

Odpowiedzi:

57

Luki bezpieczeństwa, które możesz otworzyć, mają związek z wstrzyknięciem kodu - wstrzyknięciem HTML, wstrzyknięciem JavaScript lub wstrzyknięciem SQL.

Domyślne ustawienia chronią Cię przed atakami pół wydajnie, uniemożliwiając działanie typowych strategii wstrzykiwania. Im więcej domyślnych zabezpieczeń usuwasz, tym więcej musisz myśleć o tym, co robisz z danymi wejściowymi dostarczanymi przez adresy URL, kwerendy żądań GET, dane żądań POST, nagłówki HTTP i tak dalej ...

Na przykład, jeśli tworzysz dynamiczne zapytania SQL na podstawie idparametru Twojej metody akcji, na przykład:

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

(... co NIE jest dobrym pomysłem), domyślna ochrona, wprowadzona przez platformę .NET, może powstrzymać niektóre z bardziej niebezpiecznych scenariuszy, takich jak użytkownik żądający tego adresu URL:

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

Cała idea polega na traktowaniu każdej części adresów URL i innych danych wejściowych do metod działania jako możliwych zagrożeń. Domyślne ustawienie zabezpieczeń zapewnia część tej ochrony. Każde domyślne ustawienie zabezpieczeń, które zmieniasz, otwiera się na nieco więcej potencjalnych zagrożeń, z którymi musisz sobie poradzić ręcznie.

Zakładam, że nie tworzysz zapytań SQL w ten sposób. Ale bardziej podstępne rzeczy pojawiają się, gdy przechowujesz dane wejściowe użytkownika w swojej bazie danych, a następnie wyświetlasz je. Zły użytkownik może przechowywać JavaScript lub HTML w twojej bazie danych, które wyjdą niezakodowane, co z kolei zagrozi innym użytkownikom twojego systemu.

Anders Tornblad
źródło
6

Zagrożenie dla bezpieczeństwa

To ustawienie allowDoubleEscapingma zastosowanie tylko do path(cs-uri-stem) i najlepiej jest wyjaśnione przez podwójne kodowanie OWASP . Technika ta służy do obejścia kontroli bezpieczeństwa poprzez dwukrotne kodowanie adresu URL żądania. Na przykładzie adresu URL:

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

Załóżmy, że istnieją mechanizmy zabezpieczeń specjalnie dla /product/tags/for+families. Nadchodzi żądanie, dla /product/tags/for%252Bfamiliesktórego jest to ten sam zasób, ale nie jest ono sprawdzane przez wyżej wymienione mechanizmy bezpieczeństwa. Użyłem uogólnionego terminu kontroli bezpieczeństwa, ponieważ może to być wszystko, na przykład wymaganie uwierzytelnionego użytkownika, sprawdzanie SQLi itp.

Dlaczego usługi IIS blokują?

Znak plus (+) jest znakiem zastrzeżonym zgodnie z RFC2396 :

Wiele identyfikatorów URI zawiera komponenty składające się z pewnych znaków specjalnych lub rozdzielane nimi. Znaki te nazywane są „zastrzeżonymi”, ponieważ ich użycie w składniku URI jest ograniczone do ich zastrzeżonego celu. Jeśli dane składnika URI byłyby w konflikcie z zarezerwowanym celem, to dane będące w konflikcie muszą zostać zabezpieczone przed utworzeniem URI.

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

Wade Hilmo ma doskonały post zatytułowany Jak IIS blokuje znaki w adresach URL . Podano wiele informacji i tła. Część dotycząca znaku plus jest następująca:

Więc allowDoubleEscaping / VerifyNormalization wydaje się całkiem proste. Dlaczego powiedziałem, że powoduje to zamieszanie? Problem występuje, gdy w adresie URL pojawia się znak „+”. Znak „+” nie wydaje się być znakiem zmiany znaczenia, ponieważ nie zawiera „%”. Ponadto dokument RFC 2396 stwierdza, że ​​jest to znak zastrzeżony, który można zawrzeć w adresie URL, jeśli ma on postać ucieczki (% 2b). Ale gdy allowDoubleEscaping jest ustawione na domyślną wartość false, zablokujemy go nawet w postaci ucieczki. Przyczyna tego jest historyczna: we wczesnych latach HTTP znak „+” był uważany za skrót od znaku spacji. Niektóre konfiguratory kanoniczne po otrzymaniu adresu URL zawierającego znak „+” przekonwertują go na spację. Z tego powodu uważamy, że znak „+” w adresie URL nie jest kanoniczny. Nie udało mi się znaleźć żadnego odniesienia do dokumentu RFC, który odwołuje się do tego traktowania „+”,

Z własnego doświadczenia wiem, że w logach IIS spacje żądań są zastępowane znakiem plus. Posiadanie znaku plus w nazwie może powodować zamieszanie podczas analizowania dzienników.

Rozwiązanie

Istnieją trzy sposoby rozwiązania tego problemu i dwa sposoby, aby nadal używać znaku plus.

  1. allowDoubleEscaping=true- Pozwoli to na podwójną ucieczkę dla całej witryny / aplikacji. W zależności od treści może to być co najmniej niepożądane. Następujące polecenie zostanie ustawione allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- Filtrowanie żądań oferuje podejście do białej listy. Dodając tę ​​ścieżkę adresu URL do alwaysAllowedUrls, żądanie nie będzie sprawdzane przez żadne inne ustawienia filtrowania żądań i będzie kontynuowane w potoku żądań usług IIS. Problem polega na tym, że funkcja filtrowania żądań nie sprawdzi żądania pod kątem:

    • Limity żądań: maxContentLength, maxUrl, maxQueryString
    • Czasowniki
    • Zapytanie - parametry ciągu zapytania nie będą sprawdzane
    • Podwójna ucieczka
    • High Bit Characters
    • Poproś o reguły filtrowania
    • Prośby o limity nagłówków

    Następujące polecenie zostanie dodane /product/tags/for+familiesdo alwaysAllowedUrlsdomyślnej witryny sieci Web.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. Zmień nazwę - tak, po prostu zmień nazwę pliku / folderu / kontrolera / itp. Jeśli to możliwe. To najłatwiejsze rozwiązanie.

user2320464
źródło
Aby umożliwić DoubleEscaping podczas programowania za pomocą IIS Express, oto co zrobiłem: stackoverflow.com/q/56463044/381082
DeveloperDan,
3

Przygotowałem do tego robotę. więc kiedy chcesz umieścić zaszyfrowany ciąg wewnątrz adresu URL dla (IIS), musisz go wyczyścić z brudnych: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; a kiedy chcesz go odszyfrować i użyć ponownie, musisz go ponownie zabrudzić przed odszyfrowaniem (aby uzyskać pożądany wynik).

Oto mój kod, mam nadzieję, że komuś pomoże:

 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;
        }
Mark Dibeh
źródło
Co to jest pntGlm?
StuperUser
@StuperUser to tylko losowe znaki
Mark Dibeh
1
Ciąg powinien być base64zakodowany zamiast korzystać z tej techniki zastępowania. Na przykład uwierzytelnianie podstawowe używa base64do kodowania przesłanych poświadczeń, ponieważ mogą one zawierać znaki specjalne / zastrzeżone.
user2320464
Problem z base64 jest / jest postacią base64 i może zepsuć trasy
Garr Godfrey
1

Więc napotkałem to, gdy wywoływałem API z aplikacji MVC. Zamiast otwierać lukę w zabezpieczeniach, zmodyfikowałem ścieżkę.

Po pierwsze, NIE ZALECAM wyłączania tego ustawienia. Bardziej właściwe jest zmodyfikowanie projektu aplikacji / zasobu (np. Zakodowanie ścieżki, przekazanie danych w nagłówku lub w treści).

Chociaż jest to starszy post, pomyślałem, że podzielę się, w jaki sposób można rozwiązać ten błąd, jeśli otrzymujesz to z wywołania interfejsu API przy użyciu metody HttpUtility.UrlPathEncode w System.Web .

Używam RestSharp do wywoływania, więc mój przykład używa RestRequest:

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

Daje to ścieżkę równą:

/ produkt / tagi / dla% 2Bfamilies

Z drugiej strony NIE twórz dynamicznego zapytania na podstawie danych wprowadzonych przez użytkownika. POWINIENEŚ zawsze używać SqlParameter . Z punktu widzenia bezpieczeństwa niezwykle ważne jest również zwrócenie wartości z odpowiednim kodowaniem, aby zapobiec atakom polegającym na wstrzykiwaniu.

~ Pozdrawiam

Rogala
źródło
0

Zakoduj zaszyfrowany ciąg oddzielony:

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

Odszyfruj zaszyfrowany ciąg oddzielony:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
unvascorriendo
źródło