Il modo migliore per gestire la sicurezza ed evitare XSS con gli URL inseriti dall’utente

Abbiamo un’applicazione ad alta sicurezza e vogliamo consentire agli utenti di inserire URL che altri utenti vedranno.

Questo introduce un alto rischio di attacchi XSS – un utente potrebbe potenzialmente inserire javascript che un altro utente finirà di eseguire. Poiché teniamo dati sensibili, è essenziale che ciò non accada mai.

Quali sono le migliori pratiche nell’affrontare questo? La whitelist o il modello di fuga di sicurezza è abbastanza buono?

Qualche consiglio su come gestire i reindirizzamenti (“questo link esce dal nostro sito” su una pagina di avviso prima di seguire il link, ad esempio)

C’è un argomento per non supportare affatto i collegamenti inseriti dall’utente?


Una precisazione:

In pratica, i nostri utenti vogliono inserire:

stackoverflow.com

E farlo inviare a un altro utente:

stackoverflow.com 

Quello di cui mi preoccupo davvero è che usano questo in un hack XSS. Ad esempio, inseriscono:

alert ( ‘hacked!’);

Quindi altri utenti ottengono questo link:

 stackoverflow.com 

Il mio esempio è solo per spiegare il rischio: sono ben consapevole del fatto che javascript e URL sono cose diverse, ma lasciandoli inserire questi ultimi potrebbero essere in grado di eseguire il primo.

Saresti stupito di quanti siti puoi rompere con questo trucco – l’HTML è anche peggio. Se sanno di avere a che fare con i collegamenti, sanno anche di disinfettare , e riferimenti CSS intelligenti?

Sto lavorando in un ambiente ad alta sicurezza – un singolo hack XSS potrebbe comportare perdite molto alte per noi. Sono felice di poter produrre un Regex (o usare uno dei suggerimenti eccellenti finora) che potrebbe escludere tutto quello che potrei pensare, ma sarebbe sufficiente?

Se pensi che gli URL non possano contenere codice, ripensaci!

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

Leggilo e piangi.

Ecco come lo facciamo su Stack Overflow:

 ///  /// returns "safe" URL, stripping anything outside normal charsets for URL ///  public static string SanitizeUrl(string url) { return Regex.Replace(url, @"[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]", ""); } 

Il processo di rendere un collegamento “sicuro” dovrebbe seguire tre o quattro passaggi:

  • Unescape / ricodifica la stringa che ti è stata data (RSnake ha documentato una serie di trucchi su http://ha.ckers.org/xss.html che utilizzano le codifiche di escape e UTF).
  • Pulisci il collegamento: i regex sono un buon inizio – assicurati di troncare la stringa o buttala via se contiene un “(o qualsiasi altra cosa tu usi per chiudere gli attributi nel tuo output); se stai facendo i link solo come riferimento ad altre informazioni puoi anche forzare il protocollo alla fine di questo processo – se la parte precedente ai primi due punti non è “http” o “https” quindi aggiungi “http: //” all’inizio. Ciò ti consente di creare collegamenti da input incompleti in quanto un utente digita in un browser e ti dà l’ultima possibilità di incappare in tutto ciò che qualcuno ha cercato di intrufolare.
  • Verifica che il risultato sia un URL ben formato (protocollo: //host.dominio [: porta] [/ percorso] [/ [file]] [? QueryField = queryValue] [#anchor]).
  • È ansible controllare il risultato in una blacklist del sito o provare a recuperarlo attraverso una sorta di controllo del malware.

Se la sicurezza è una priorità, mi auguro che gli utenti perdonino un po ‘di paranoia in questo processo, anche se finiscono per gettare via alcuni collegamenti sicuri.

Utilizzare una libreria, come l’API OWASP-ESAPI:

Leggi quanto segue:

Per esempio:

 $url = "http://stackoverflow.com"; // eg, $_GET["user-homepage"]; $esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml $sanitizer = ESAPI::getSanitizer(); $sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url ); 

Un altro esempio è l’uso di una funzione integrata. La funzione filter_var di PHP è un esempio:

 $url = "http://stackoverflow.com"; // eg, $_GET["user-homepage"]; $sanitized_url = filter_var($url, FILTER_SANITIZE_URL); 

L’uso di filter_var consente chiamate javascript e filtra schemi che non sono né httphttps . L’uso di OWASP ESAPI Sanitizer è probabilmente l’opzione migliore.

Ancora un altro esempio è il codice di WordPress :

Inoltre, poiché non c’è modo di sapere dove siano i link URL (ad esempio, potrebbe essere un URL valido, ma il contenuto dell’URL potrebbe essere malizioso), Google ha un’API di navigazione sicura che puoi chiamare:

Rolling your regex per servizi igienico-sanitari è problematico per diversi motivi:

  • A meno che non si sia Jon Skeet, il codice avrà errori.
  • Le API esistenti hanno molte ore di revisione e test dietro di loro.
  • Le API di validazione URL esistenti considerano l’internazionalizzazione.
  • Le API esistenti saranno mantenute aggiornate con gli standard emergenti.

Altri aspetti da considerare:

  • Quali schemi autorizzate (sono file:/// e telnet:// accettabile)?
  • Quali restrizioni vuoi inserire sul contenuto dell’URL (sono accettabili gli URL di malware)?

Solo HTMLEncode i link quando li metti in uscita. Assicurati di non consentire javascript: collegamenti. (È meglio disporre di una whitelist di protocolli accettati, ad esempio http, https e mailto.)

Non si specifica la lingua dell’applicazione, presumo quindi ASP.NET e, per questo, è ansible utilizzare la libreria di scripting del sito di Microsoft Anti-Cross

È molto facile da usare, tutto ciò di cui hai bisogno è un inclusione e questo è 🙂

Mentre sei sull’argomento, perché non dare una lettura su Linee guida di progettazione per Secure Web Applications

Se qualsiasi altra lingua …. se esiste una libreria per ASP.NET, deve essere disponibile anche per altri tipi di linguaggio (PHP, Python, ROR, ecc.)

Che ne dici di non visualizzarli come link? Basta usare il testo.

Combinato con un avvertimento per procedere a proprio rischio potrebbe essere sufficiente.

Inoltre , vedi anche Devo disinfettare il markup HTML per un CMS ospitato? per una discussione sulla sanitizzazione dell’input dell’utente

Potresti usare un codice esadecimale per convertire l’intero URL e inviarlo al tuo server. In questo modo il cliente non capirebbe il contenuto a prima vista. Dopo aver letto il contenuto, potresti decodificare l’URL del contenuto =? e inviarlo al browser.

Consentire un URL e consentire JavaScript sono 2 cose diverse.