doppia sequenza di escape all'interno di un URL: il modulo di filtraggio delle richieste è configurato per negare una richiesta che contiene una doppia sequenza di escape


86

Sulla mia applicazione ASP.NET MVC, sto cercando di implementare un URL come di seguito:

/ prodotto / tag / per + famiglie

Quando provo a eseguire la mia applicazione con le configurazioni predefinite, ricevo questo messaggio con il codice di risposta 404.11:

Errore HTTP 404.11 - Non trovato

Il modulo di filtraggio delle richieste è configurato per negare una richiesta che contiene una doppia sequenza di escape.

Posso aggirare questo errore implementando il codice seguente all'interno del mio web.config:

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

Quindi, ora non ne ricevo 404.11.

Quello che mi chiedo è che tipo di falle di sicurezza sto aprendo con questa implementazione.

BTW, la mia applicazione è sotto .Net Framework 4.0e funziona sotto IIS 7.5.


È possibile raggiungere la risorsa desiderata utilizzando /product/tags/for%20familiesinvece? Quindi hai una soluzione alternativa per gli ID contenenti spazi. O sono completamente fuori di qui?
Anders Tornblad

@atornblad un po 'fuori immagino. La mia domanda: quello che mi chiedo è che tipo di falle di sicurezza sto aprendo con questa implementazione.
tugberk

5
IIS lancia il carattere "+", che è il comportamento predefinito di Microsoft.
Todd Shelton

Risposte:


57

I buchi di sicurezza che potresti aprire hanno a che fare con l'iniezione di codice: HTML injection, JavaScript injection o SQL injection.

Le impostazioni predefinite ti proteggono dagli attacchi in modo semi-efficiente non consentendo il funzionamento delle strategie di iniezione comuni. Più sicurezza predefinita rimuovi, più devi pensare a cosa fare con l'input fornito tramite URL, stringhe di richiesta GET, dati di richiesta POST, intestazioni HTTP e così via ...

Ad esempio, se stai creando query SQL dinamiche basate sul idparametro del tuo metodo di azione, in questo modo:

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

(... che NON è una buona idea), la protezione predefinita, messa in atto dal framework .NET, potrebbe bloccare alcuni degli scenari più pericolosi, come l'utente che richiede questo URL:

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

L'idea è di trattare ogni parte degli URL e altri input ai metodi di azione come possibili minacce. L'impostazione di sicurezza predefinita fornisce una parte di quella protezione per te. Ogni impostazione di sicurezza predefinita che modifichi si apre per un po 'più di potenziale danno che devi gestire manualmente.

Presumo che tu non stia costruendo query SQL in questo modo. Ma le cose più subdole arrivano quando memorizzi l'input dell'utente nel tuo database, per poi visualizzarlo in seguito. L'utente malvagio potrebbe memorizzare JavaScript o HTML nel tuo database che non sono codificati, il che a sua volta minaccia gli altri utenti del tuo sistema.


6

Rischio per la sicurezza

L'impostazione allowDoubleEscapingsi applica solo a path(cs-uri-stem) ed è meglio spiegata da OWASP Double Encoding . La tecnica viene utilizzata per aggirare i controlli di sicurezza codificando due volte la richiesta. Usando il tuo URL come esempio:

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

Supponiamo che ci siano controlli di sicurezza specifici per /product/tags/for+families. Arriva una richiesta per la /product/tags/for%252Bfamiliesquale è la stessa risorsa sebbene non sia controllata dai suddetti controlli di sicurezza. Ho usato il termine generalizzato di controlli di sicurezza perché potrebbero essere qualsiasi cosa come la richiesta di un utente autenticato, il controllo di SQLi, ecc.

Perché IIS si blocca?

Il segno più (+) è un carattere riservato per RFC2396 :

Molti URI includono componenti costituiti o delimitati da determinati caratteri speciali. Questi caratteri sono chiamati "riservati", poiché il loro utilizzo all'interno del componente URI è limitato allo scopo riservato. Se i dati per un componente URI sono in conflitto con lo scopo riservato, è necessario eseguire l'escape dei dati in conflitto prima di formare l'URI.

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

Wade Hilmo ha un eccellente post intitolato Come IIS blocca i caratteri negli URL . Sono fornite molte informazioni e background. La parte specifica per il segno più è la seguente:

Quindi allowDoubleEscaping / VerifyNormalization sembra piuttosto semplice. Perché ho detto che causa confusione? Il problema è quando un carattere "+" appare in un URL. Il carattere "+" non sembra essere sottoposto a escape, poiché non include un "%". Inoltre, RFC 2396 lo rileva come un carattere riservato che può essere incluso in un URL quando è in formato escape (% 2b). Ma con allowDoubleEscaping impostato sul valore predefinito false, lo bloccheremo anche in forma di escape. La ragione di ciò è storica: nei primi giorni di HTTP, un carattere "+" era considerato una scorciatoia per un carattere spazio. Alcuni canonicalizzatori, quando viene fornito un URL che contiene un "+", lo convertiranno in uno spazio. Per questo motivo, consideriamo un "+" non canonico in un URL. Non sono stato in grado di trovare alcun riferimento a una RFC che richiama questo trattamento "+",

Per esperienza personale so che quando IIS registra una richiesta, gli spazi vengono sostituiti con un segno più. La presenza di un segno più nel nome può causare confusione durante l'analisi dei log.

Soluzione

Esistono tre modi per risolvere questo problema e due modi per utilizzare ancora il segno più.

  1. allowDoubleEscaping=true- Ciò consentirà una doppia fuga per l'intero sito Web / applicazione. A seconda del contenuto, questo potrebbe essere a dir poco indesiderabile. Il seguente comando verrà impostato allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- Request Filtering offre un approccio da whitelist. Aggiungendo tale percorso URL a alwaysAllowedUrls, la richiesta non verrà controllata da altre impostazioni di filtro richieste e continuerà nella pipeline delle richieste IIS. La preoccupazione qui è che il filtro delle richieste non controllerà la richiesta di:

    • Limiti della richiesta: maxContentLength, maxUrl, maxQueryString
    • Verbi
    • Query: i parametri della stringa di query non verranno controllati
    • Doppia fuga
    • Caratteri bit alti
    • Richiedi regole di filtro
    • Richiedi limiti di intestazione

    Il seguente comando verrà aggiunto /product/tags/for+familiesal alwaysAllowedUrlssito Web predefinito.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. Rinomina : sì, rinomina semplicemente il file / cartella / controller / ecc. se possibile. Questa è la soluzione più semplice.


Per consentire DoubleEscaping durante lo sviluppo con IIS Express, ecco cosa ho fatto: stackoverflow.com/q/56463044/381082
DeveloperDan

5

Ho fatto un lavoro intorno a questo. quindi quando vuoi inserire la stringa codificata all'interno dell'URL per (IIS) devi pulirlo da sporco: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; e quando vuoi decriptarlo e usarlo di nuovo, devi sporcarlo di nuovo prima di decriptarlo (per ottenere il risultato desiderato).

Ecco il mio codice, spero che aiuti qualcuno:

 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;
        }

Cos'è pntGlm?
StuperUser

@StuperUser solo personaggi casuali
Mark Dibeh

1
La stringa dovrebbe essere base64codificata invece di utilizzare questa tecnica di sostituzione. Ad esempio, l'autenticazione di base utilizza base64per codificare le credenziali inviate in quanto potrebbe contenere caratteri speciali / riservati.
user2320464

il problema con base64 è / è un personaggio base64 e può rompere le rotte
Garr Godfrey

1

Quindi mi sono imbattuto in questo quando stavo chiamando un'API da un'app MVC. Invece di aprire il buco di sicurezza, ho modificato il mio percorso.

Prima di tutto, consiglio di NON disabilitare questa impostazione. È più appropriato modificare il design dell'applicazione / risorsa (es. Codificare il percorso, passare i dati in un'intestazione o nel corpo).

Sebbene questo sia un post precedente, ho pensato di condividere come potresti risolvere questo errore se lo ricevi da una chiamata a un'API utilizzando il metodo HttpUtility.UrlPathEncode in System.Web .

Uso RestSharp per effettuare chiamate, quindi il mio esempio sta usando RestRequest:

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

Questo produce un percorso uguale a:

/ product / tags / per% 2Bfamilies

In un'altra nota, NON creare una query dinamica basata sugli input di un utente. DOVREBBE sempre usare un SqlParameter . Inoltre, è estremamente importante dal punto di vista della sicurezza restituire i valori con la codifica appropriata per prevenire attacchi injection.

~ Salute


0

Codifica la stringa crittografata in modo separato:

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

Decodifica la stringa crittografata separatamente:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.