web-dev-qa-db-fra.com

Meilleure façon de gérer la sécurité et d'éviter XSS avec les URL entrées par l'utilisateur

Nous avons une application haute sécurité et nous voulons permettre aux utilisateurs de saisir des URL que d'autres utilisateurs verront.

Cela introduit un risque élevé de piratage XSS - un utilisateur peut éventuellement entrer du code JavaScript qu'un autre utilisateur finira par exécuter. Puisque nous détenons des données sensibles, il est essentiel que cela ne se produise jamais.

Quelles sont les meilleures pratiques en la matière? Une liste blanche de sécurité ou un modèle d’échappement est-il suffisant? 

Tout conseil sur le traitement des redirections (message "ce lien sort de notre site" sur une page d'avertissement avant de suivre le lien, par exemple)

Existe-t-il un argument pour ne pas supporter du tout les liens saisis par l'utilisateur?


Clarification:

Fondamentalement, nos utilisateurs veulent entrer: 

stackoverflow.com

Et le faire sortir à un autre utilisateur:

<a href="http://stackoverflow.com">stackoverflow.com</a>

Ce qui me préoccupe vraiment, c’est qu’ils utilisent cela dans un hack XSS. C'est à dire. ils entrent:

alerte ('piraté!');

Donc, les autres utilisateurs obtiennent ce lien:

<a href="alert('hacked!');">stackoverflow.com</a>

Mon exemple est juste pour expliquer le risque - je sais bien que javascript et les URL sont des choses différentes, mais en les laissant entrer ce dernier, ils pourraient peut-être exécuter le premier.

Vous seriez surpris de voir combien de sites vous pouvez briser avec cette astuce - HTML est encore pire. S'ils savent manipuler des liens, savent-ils également comment désinfecter les références <iframe>, <img> et CSS intelligentes?

Je travaille dans un environnement hautement sécurisé - un simple piratage XSS pourrait nous occasionner de très lourdes pertes. Je suis heureux de pouvoir produire un regex (ou d'utiliser l'une des excellentes suggestions jusqu'à présent) qui puisse exclure tout ce à quoi je peux penser, mais est-ce suffisant?

48
Keith

Si vous pensez que les URL ne peuvent pas contenir de code, détrompez-vous!

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

Lisez cela et pleurez.

Voici comment nous le faisons sur Stack Overflow:

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

Pour rendre un lien "sûr", vous devez suivre trois ou quatre étapes:

  • Décompressez/ré-encodez la chaîne qui vous a été donnée (RSnake a documenté un certain nombre de trucs à  http://ha.ckers.org/xss.html qui utilisent des codages d'échappement et UTF).
  • Nettoyez le lien: les expressions rationnelles sont un bon début - assurez-vous de tronquer la chaîne ou de la jeter si elle contient un "(ou tout ce que vous utilisez pour fermer les attributs dans votre sortie); si vous faites les liens uniquement comme références pour d'autres informations, vous pouvez également forcer le protocole à la fin de ce processus - si la partie précédant les deux-points n'est pas "http" ou "https", ajoutez ensuite "http: //" au début. Cela vous permet de créer des liens provenant d'entrées incomplètes, comme un utilisateur taperait dans un navigateur, et vous donneront une dernière chance de tromper tout le mal que quelqu'un a tenté de se faufiler.
  • Vérifiez que le résultat est une URL bien formée (protocole: //Host.domain [: port] [/ chemin] [/ [fichier]] [? QueryField = queryValue] [#anchor]).
  • Vous pouvez éventuellement comparer le résultat à une liste noire de sites ou essayer de le récupérer via un vérificateur de programmes malveillants.

Si la sécurité est une priorité, j'espère que les utilisateurs pardonneront un peu de paranoïa dans ce processus, même s'il finit par jeter des liens sûrs.

13
Bell

Utilisez une bibliothèque, telle que l'API OWASP-ESAPI:

Lisez ce qui suit:

Par exemple:

$url = "http://stackoverflow.com"; // e.g., $_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 autre exemple consiste à utiliser une fonction intégrée. La fonction PHP filter_var en est un exemple:

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

Utiliser filter_varpermet les appels javascript et filtre les régimes qui ne sont ni http ni https. L'utilisation de OWASP ESAPI Sanitizer est probablement la meilleure option.

Encore un autre exemple est le code de WordPress :

De plus, comme il n’existe aucun moyen de savoir où l’URL est liée (par exemple, il peut s’agir d’une URL valide, mais le contenu de cette URL peut être malicieux), Google dispose d’une API navigation sûre que vous pouvez appeler:

Faire rouler sa propre regex pour l'assainissement pose problème pour plusieurs raisons:

  • Sauf si vous êtes Jon Skeet, le code comportera des erreurs.
  • Les API existantes disposent de nombreuses heures d'analyse et de test.
  • Les API de validation d'URL existantes prennent en compte l'internationalisation.
  • Les API existantes seront tenues à jour avec les normes émergentes.

Autres questions à prendre en compte:

  • Quels modèles autorisez-vous (file:/// et telnet:// sont-ils acceptables)?
  • Quelles restrictions voulez-vous imposer au contenu de l'URL (les URL de programmes malveillants sont-elles acceptables)?
8
Dave Jarvis

Vous ne spécifiez pas la langue de votre application, je présume alors ASP.NET et vous pouvez utiliser pour cela la Bibliothèque de scripts anti-site multiple de Microsoft

Il est très facile à utiliser, tout ce dont vous avez besoin est un include, et c'est tout :)

Pendant que vous êtes sur le sujet, pourquoi ne pas lire/ Directives de conception pour les applications Web sécurisées

S'il existe une autre langue .... s'il existe une bibliothèque pour ASP.NET, elle doit également être disponible pour d'autres types de langage (PHP, Python, ROR, etc.)

3
balexandre

Juste HTMLEncode les liens lorsque vous les sortez. Assurez-vous de ne pas autoriser les liens javascript:. (Il est préférable d’avoir une liste blanche de protocoles acceptés, tels que http, https et mailto.)

3
Patrick McElhaney

Pourquoi ne pas les afficher sous forme de lien? Il suffit d'utiliser le texte.

Combiné avec un avertissement de procéder à vos propres risques peut suffire.

addition - voir aussi Devrais-je nettoyer le balisage HTML pour un CMS hébergé? pour une discussion sur la désinfection des entrées de l'utilisateur

1
warren

Dans mon projet écrit en JavaScript, j'utilise cette regex comme liste blanche:

 url.match(/^((https?|ftp):\/\/|\.{0,2}\/)/)

la seule limite est que vous devez placer ./ devant les fichiers du même répertoire, mais je pense pouvoir vivre avec cela.

0
jcubic

Pour les pythonistes, essayez Scrapy's w3lib .

OWASP ESAPI est antérieur à Python 2.7 et est archivé sur le le code Google maintenant disparu .

0
Zach Valenta