web-dev-qa-db-fra.com

Comment prévenir XSS avec HTML / PHP?

Comment puis-je empêcher XSS (script intersite) d'utiliser uniquement HTML et PHP?

J'ai lu de nombreux autres articles sur ce sujet, mais je n'ai pas trouvé d'article qui explique clairement et de façon concise comment prévenir réellement XSS.

236
TimTim

En principe, vous devez utiliser la fonction htmlspecialchars() chaque fois que vous souhaitez envoyer au navigateur une information provenant de la saisie de l'utilisateur.

La manière correcte d’utiliser cette fonction ressemble à ceci:

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

Google Code University propose également ces vidéos très éducatives sur la sécurité Web:

272
Alix Axel

Une de mes références préférées OWASP est la script intersite explication car s'il existe un grand nombre de vecteurs d'attaque XSS, le respect de quelques règles permet de se défendre grandement contre la majorité d'entre eux!

C'est Aide-mémoire de sécurité PHP

37
Wahyu Kristianto

L'une des étapes les plus importantes consiste à supprimer toute entrée d'utilisateur avant son traitement et/ou son rendu au navigateur. PHP possède des fonctions " filtre " utilisables.

La forme utilisée par les attaques XSS consiste généralement à insérer un lien vers du code JavaScript hors site contenant une intention malveillante pour l'utilisateur. En savoir plus à ce sujet ici .

Vous voudrez également tester votre site - je peux recommander le module complémentaire Firefox XSS Me .

14
James Kolpack

Dans l'ordre de préférence:

  1. Si vous utilisez un moteur de modélisation (par exemple, Twig, Smarty, Blade), vérifiez qu'il offre un échappement sensible au contexte. Je sais par expérience que Twig le fait. {{ var|e('html_attr') }}
  2. Si vous souhaitez autoriser le code HTML, utilisez le purificateur HTML . Même si vous pensez n'accepter que Markdown ou ReStructuredText, vous souhaitez toujours purifier le code HTML de la sortie de ces langages de balisage.
  3. Sinon, utilisez htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset) et assurez-vous que le reste de votre document utilise le même jeu de caractères que $charset. Dans la plupart des cas, 'UTF-8' est le jeu de caractères souhaité.

Assurez-vous également que vous échappez à la sortie, pas à l’entrée .

9
Scott Arciszewski

Répondez à ceci en tant que référence consolidée à partir de la version bêta de la SO Documentation qui est en train de passer hors ligne.

Problème

Le script intersite est l’exécution involontaire de code à distance par un client Web. Toute application Web peut s’exposer à XSS si elle prend les entrées d’un utilisateur et les affiche directement sur une page Web. Si l'entrée inclut HTML ou JavaScript, le code à distance peut être exécuté lorsque ce contenu est rendu par le client Web.

Par exemple, si un côté tiers contient un fichier JavaScript:

// http://example.com/runme.js
document.write("I'm running");

Et une application PHP génère directement une chaîne qui y est passée:

<?php
echo '<div>' . $_GET['input'] . '</div>';

Si un paramètre GET non contrôlé contient <script src="http://example.com/runme.js"></script>, le résultat du script PHP sera:

<div><script src="http://example.com/runme.js"></script></div>

Le code JavaScript tiers s’exécutera et l’utilisateur verra "j’exécute" sur la page Web.

Solution

En règle générale, ne faites jamais confiance aux données provenant d'un client. Chaque valeur GET, POST et cookie peut être quelconque et doit donc être validée. Lorsque vous indiquez l'une de ces valeurs, échappez-les afin qu'elles ne soient pas évaluées de manière inattendue.

N'oubliez pas que même dans les applications les plus simples, les données peuvent être déplacées et qu'il sera difficile de garder une trace de toutes les sources. Par conséquent, il est recommandé de toujours échapper à la sortie.

PHP fournit quelques moyens d'échapper à la sortie en fonction du contexte.

Fonctions de filtrage

Les fonctions de filtre PHP permettent aux données d'entrée du script php d'être nettoyées ou validées dans de plusieurs façons . Ils sont utiles lors de la sauvegarde ou de la sortie d’une entrée client.

Codage HTML

htmlspecialchars convertira tous les "caractères spéciaux HTML" en leurs codages HTML, ce qui signifie qu'ils seront alors et non traités au format HTML standard. Pour corriger notre exemple précédent en utilisant cette méthode:

<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';

Serait sortie:

<div>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

Tout ce qui se trouve à l'intérieur de la balise <div> ne sera pas interprété comme une balise JavaScript par le navigateur, mais plutôt comme un simple nœud de texte. L'utilisateur verra en toute sécurité:

<script src="http://example.com/runme.js"></script>

Encodage d'URL

Lors de la sortie d'une URL générée dynamiquement, PHP fournit la fonction urlencode pour générer en toute sécurité des URL valides. Ainsi, par exemple, si un utilisateur est capable de saisir des données qui font partie d’un autre paramètre GET:

<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';

Toute entrée malveillante sera convertie en un paramètre d'URL codé.

Utilisation de bibliothèques externes spécialisées ou de listes OWASP AntiSamy

Parfois, vous voudrez envoyer du HTML ou un autre type d’entrées de code. Vous devrez maintenir une liste de mots autorisés (liste blanche) et non autorisés (liste noire).

Vous pouvez télécharger des listes standard disponibles sur le site Web de OWASP AntiSamy . Chaque liste est adaptée à un type d'interaction spécifique (ebay api, tinyMCE, etc.). Et c'est open source.

Il existe des bibliothèques existantes pour filtrer le code HTML et empêcher les attaques XSS dans le cas général, en effectuant au moins aussi bien que les listes AntiSamy une utilisation très simple. Par exemple, vous avez un purificateur HTML

6
Matt S

De nombreux frameworks aident à gérer XSS de différentes manières. Si vous avez des problèmes avec les XSS, nous pouvons utiliser filter_input_array (disponible dans PHP 5> = 5.2.0, PHP 7.) I En règle générale, cet extrait de code sera ajouté à mon SessionController, car tous les appels y sont passés avant qu'un autre contrôleur n'interagisse avec les données. De cette manière, toutes les entrées utilisateur sont désinfectées dans un emplacement central. Si cela est fait au début d'un projet ou avant que votre base de données ne soit empoisonnée, vous ne devriez pas avoir de problèmes au moment de la sortie ... arrête les déchets, les déchets.

/* Prevent XSS input */
$_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;

Ce qui précède supprimera TOUTES balises HTML et script. Si vous avez besoin d’une solution autorisant les balises sûres, basée sur une liste blanche, consultez HTML Purifier .


Si votre base de données est déjà empoisonnée ou si vous souhaitez utiliser XSS au moment de la sortie, OWASP recommande de créer une fonction d'encapsulation personnalisée pour echo et de l'utiliser PARTOUT où que vous produisiez des données fournies par l'utilisateur. valeurs:

//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
   return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
   echo xssafe($data);
}
4
webaholik
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Remove javascript: and vbscript: protocols
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do
{
    // Remove really unwanted tags
    $old_data = $data;
    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

// we are done...
return $data;
}
2
Abdo-Host

Vous pouvez également définir certains en-têtes de réponse HTTP liés à XSS via header(...)

Protection X-XSS "1; mode = bloc"

pour être sûr, le mode de protection XSS du navigateur est activé.

Content-Security-Policy "default-src 'self'; ..."

pour activer la sécurité du contenu côté navigateur. Voir celui-ci pour plus de détails sur la politique de sécurité du contenu (CSP): http://content-security-policy.com/ > Configurer en particulier CSP pour bloquer les scripts en ligne et les sources de script externes est utile contre XSS.

pour un ensemble général d’en-têtes de réponses HTTP utiles concernant la sécurité de votre application Web, consultez OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers

1
chris

Utilisez htmlspecialchars sur PHP. Sur HTML, essayez d'éviter d'utiliser:

element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);

var est contrôlé par l'utilisateur .

Evidemment, essayez également d'éviter eval(var), si vous devez utiliser l'un d'eux, essayez JS leur échapper, HTML leur échapper et vous devrez peut-être en faire plus, mais pour les bases cela devrait suffire.

0
Pablo