web-dev-qa-db-fra.com

Quelles sont les meilleures pratiques pour éviter les attaques xss dans un site PHP

J'ai PHP configuré pour que les guillemets magiques soient activés et que les registres globaux soient désactivés.

Je fais de mon mieux pour toujours appeler htmlentities () pour tout ce que je génère et qui est dérivé de l'entrée utilisateur.

Je recherche également occasionnellement ma base de données pour les choses courantes utilisées dans xss jointes telles que ...

<script

Que dois-je faire d'autre et comment puis-je m'assurer que les choses que j'essaie de faire sont toujours terminées.

65
Rik Heywood

Échapper à l'entrée n'est pas le meilleur que vous puissiez faire pour une prévention XSS réussie. La sortie doit également être échappée. Si vous utilisez le moteur de modèle Smarty, vous pouvez utiliser |escape:'htmlall' modificateur pour convertir tous les caractères sensibles en entités HTML (j'utilise son propre |e modificateur qui est un alias de ce qui précède).

Mon approche de la sécurité des entrées/sorties est la suivante:

  • stocker l'entrée utilisateur non modifiée (pas d'échappement HTML en entrée, uniquement un échappement compatible DB effectué via des instructions préparées par PDO)
  • échapper sur la sortie, selon le format de sortie que vous utilisez (par exemple, HTML et JSON ont besoin de règles d'échappement différentes)
58
Michał Rudnicki

Je suis d'avis qu'il ne faut rien échapper lors de l'entrée, seulement en sortie. Depuis (la plupart du temps), vous ne pouvez pas supposer que vous savez où vont ces données. Par exemple, si vous avez un formulaire qui prend des données qui apparaissent plus tard dans un e-mail que vous envoyez, vous avez besoin d'un échappement différent (sinon un utilisateur malveillant pourrait réécrire vos en-têtes d'e-mail).

En d'autres termes, vous ne pouvez échapper qu'au tout dernier moment où les données "quittent" votre application:

  • Élément de liste
  • Écrire dans un fichier XML, échapper pour XML
  • Ecrire dans DB, échapper (pour ce SGBD particulier)
  • Écrire des e-mails, échapper aux e-mails
  • etc

Pour faire court:

  1. Vous ne savez pas où vont vos données
  2. Les données peuvent en fait se retrouver à plusieurs endroits, nécessitant un mécanisme d'échappement différent MAIS PAS LES DEUX
  3. Les données échappées pour la mauvaise cible ne sont vraiment pas sympa. (Par exemple, recevez un e-mail avec le sujet "Aller au bar de Tommy".)

Esp # 3 se produira si vous échappez des données à la couche d'entrée (ou si vous avez besoin de les échapper à nouveau, etc.).

PS: je vais seconder les conseils pour ne pas utiliser magic_quotes, ce sont des pires mal!

18
Jilles

Il y a beaucoup de façons de faire XSS (Voir http://ha.ckers.org/xss.html ) et c'est très difficile à attraper.

Je délègue personnellement cela au framework actuel que j'utilise (Code Igniter par exemple). Bien qu'il ne soit pas parfait, il pourrait attraper plus que mes routines faites à la main.

12
Christian Studer

C'est une excellente question.

Tout d'abord, n'échappez pas au texte en entrée, sauf pour le rendre sûr pour le stockage (comme être placé dans une base de données). La raison en est que vous souhaitez conserver ce qui a été entré afin de pouvoir le présenter contextuellement de différentes manières et à différents endroits. Faire des changements ici peut compromettre votre présentation ultérieure.

Lorsque vous allez présenter votre filtre de données sur ce qui ne devrait pas y être. Par exemple, s'il n'y a pas de raison pour que javascript soit là, recherchez-le et supprimez-le. Un moyen simple de le faire est d'utiliser la fonction strip_tags et de ne présenter que les balises html que vous autorisez.

Ensuite, prenez ce que vous avez et passez-le en pensant htmlentities ou htmlspecialchars pour changer ce qui est là en caractères ascii. Pour ce faire, en fonction du contexte et de ce que vous souhaitez retirer.

Je suggère également de désactiver Magic Quotes. Il a été supprimé de PHP 6 et est considéré comme une mauvaise pratique pour l'utiliser. Détails sur http://us3.php.net/magic_quotes

Pour plus de détails, consultez http://ha.ckers.org/xss.html

Ce n'est pas une réponse complète mais, espérons-le, assez pour vous aider à démarrer.

10
Matt Farina

je fais de mon mieux pour toujours appeler htmlentities () pour tout ce que je génère et qui est dérivé de l'entrée utilisateur.

.

See Joel's essay on Making Code Look Wrong for help with this

7
Mason

Je compte sur PHPTAL pour cela.

Contrairement à Smarty et à PHP simple, il échappe à toutes les sorties par défaut. C'est une grande victoire pour la sécurité, car votre site ne deviendra pas vurnelable si vous oubliez htmlspecialchars() ou |escape quelque part.

XSS est une attaque spécifique à HTML, donc la sortie HTML est le bon endroit pour l'empêcher. Vous ne devriez pas essayer de pré-filtrer les données dans la base de données, car vous pourriez avoir besoin de produire des données sur un autre support qui n'accepte pas le HTML, mais qui a ses propres risques.

4
Kornel

Bibliothèque de modèles. Ou du moins, c'est ce que les bibliothèques de modèles devraient faire. Pour empêcher XSS toutes les sorties doivent être encodées. Ce n'est pas la tâche de la logique principale d'application/de contrôle, elle doit uniquement être gérée par les méthodes de sortie.

Si vous saupoudrez htmlentities () dans votre code, la conception générale est incorrecte. Et comme vous le suggérez, vous risquez de manquer un ou deux points. C'est pourquoi la seule solution est un codage html rigoureux -> lorsque les variables de sortie sont écrites dans un flux html/xml.

Malheureusement, la plupart des bibliothèques de modèles php n'ajoutent que leur propre syntaxe de modèle, mais ne se soucient pas du codage de sortie, de la localisation, de la validation html ou de quoi que ce soit d'important. Peut-être que quelqu'un d'autre connaît une bibliothèque de modèles appropriée pour PHP?

4
user319490

Si vous êtes préoccupé par les attaques XSS, le codage de vos chaînes de sortie en HTML est la solution. Si vous vous souvenez d'encoder chaque caractère de sortie au format HTML, il n'y a aucun moyen d'exécuter une attaque XSS réussie.

En savoir plus: Sanitizing user data: How and where to do it

2
Niyaz

Personnellement, je désactiverais magic_quotes. En PHP5 +, il est désactivé par défaut et il vaut mieux coder comme s'il n'était pas là du tout car il n'échappe pas à tout et il sera supprimé de PHP6.

Ensuite, selon le type de données utilisateur que vous filtrez, vous dicterez quoi faire ensuite, par exemple si c'est juste du texte par ex. un nom, puis strip_tags(trim(stripslashes())); ou pour vérifier les plages, utilisez des expressions régulières.

Si vous attendez une certaine plage de valeurs, créez un tableau des valeurs valides et autorisez uniquement ces valeurs via (in_array($userData, array(...))).

Si vous vérifiez les nombres, utilisez is_numeric pour appliquer des nombres entiers ou transtyper en un type spécifique, cela devrait empêcher les gens d'essayer d'envoyer des chaînes à la place.

Si vous avez PHP5.2 +, pensez à regarder filter () et à utiliser cette extension qui peut filtrer divers types de données, y compris les adresses e-mail. La documentation n'est pas particulièrement bonne, mais s'améliore.

Si vous devez gérer le HTML, vous devriez envisager quelque chose comme Filtre d'entrée PHP ou Purificateur HTML . HTML Purifier validera également HTML pour la conformité. Je ne sais pas si le filtre d'entrée est toujours en cours de développement. Les deux vous permettront de définir un ensemble de balises pouvant être utilisées et les attributs autorisés.

Quoi que vous décidiez, rappelez-vous toujours, ne faites jamais confiance à quoi que ce soit entrant dans votre script PHP d'un utilisateur (vous y compris!).

2
Dave

Je trouve que l'utilisation de cette fonction aide à éliminer un grand nombre d'attaques xss possibles: http://www.codebelay.com/killxss.phps

2
barce

"Magic quotes" est un remède palliatif à certains des pires défauts XSS qui fonctionne en échappant à tout en entrée, quelque chose qui ne va pas par conception. Le seul cas où l'on voudrait l'utiliser est lorsque vous devez absolument utiliser une application PHP connue pour être écrite négligemment en ce qui concerne XSS. (Dans ce cas, vous avez de sérieux problèmes) même avec des "guillemets magiques".) Lorsque vous développez votre propre application, vous devez désactiver les "guillemets magiques" et suivre à la place les pratiques XSS-safe.

XSS, une vulnérabilité de script intersite, se produit lorsqu'une application inclut des chaînes de sources externes (entrée utilisateur, récupérées à partir d'autres sites Web, etc.) dans ses [X] HTML, CSS, ECMAscript ou autre sortie analysée par navigateur sans échappement approprié, en espérant que les caractères spéciaux comme moins que (en [X] HTML), les guillemets simples ou doubles (ECMAscript) n'apparaîtront jamais. La bonne solution consiste à toujours échapper les chaînes selon les règles du langage de sortie: utilisation d'entités en [X] HTML, barres obliques inverses en ECMAscript, etc.

Parce qu'il peut être difficile de garder une trace de ce qui n'est pas approuvé et doit être échappé, c'est une bonne idée de toujours échapper tout ce qui est une "chaîne de texte" par opposition à "texte avec balisage" dans une langue comme HTML. Certains environnements de programmation facilitent la tâche en introduisant plusieurs types de chaînes incompatibles: "chaîne" (texte normal), "chaîne HTML" (balisage HTML), etc. De cette façon, une conversion implicite directe de "chaîne" en "chaîne HTML" serait impossible, et la seule façon dont une chaîne pourrait devenir un balisage HTML est de la passer à travers une fonction d'échappement.

"Register globals", bien que la désactiver soit définitivement une bonne idée, traite un problème entièrement différent de XSS.

2
Alexey Feldgendler

Échapper à toutes les entrées utilisateur est suffisant pour la plupart des sites. Assurez-vous également que les ID de session ne se retrouvent pas dans l'URL afin qu'ils ne puissent pas être volés du lien Referer vers un autre site. De plus, si vous autorisez vos utilisateurs à envoyer des liens, assurez-vous qu'aucun javascript: les liaisons de protocole sont autorisées; ceux-ci exécuteraient un script dès que l'utilisateur clique sur le lien.

2
Konrad Rudolph

Toutes ces réponses sont excellentes, mais fondamentalement, la solution à XSS sera d'arrêter de générer des documents HTML par manipulation de chaînes.

Le filtrage des entrées est toujours une bonne idée pour n'importe quelle application.

Échapper votre sortie à l'aide de htmlentities () et d'amis devrait fonctionner tant qu'elle est utilisée correctement, mais c'est l'équivalent HTML de la création d'une requête SQL en concaténant des chaînes avec mysql_real_escape_string ($ var) - cela devrait fonctionner, mais moins de choses peuvent valider votre travail , pour ainsi dire, par rapport à une approche comme l'utilisation de requêtes paramétrées.

La solution à long terme devrait être pour les applications de construire la page en interne, peut-être en utilisant une interface standard comme le DOM, puis d'utiliser une bibliothèque (comme libxml) pour gérer la sérialisation en XHTML/HTML/etc. Bien sûr, nous sommes loin de ce qui est populaire et assez rapide, mais en attendant, nous devons construire nos documents HTML via des opérations de chaîne, et c'est intrinsèquement plus risqué.

2
Daniel Papasian
  • Ne vous fiez pas aux commentaires des utilisateurs
  • Échapper à toute sortie de texte libre
  • N'utilisez pas magic_quotes; voir s'il existe une variante spécifique au SGBD ou utiliser PDO
  • Envisagez d'utiliser des cookies HTTP uniquement dans la mesure du possible pour éviter que tout script malveillant ne puisse pirater une session
1
Rob

Vous devez au moins valider toutes les données entrant dans la base de données. Et essayez également de valider toutes les données quittant la base de données.

mysql_real_escape_string est bon pour empêcher l'injection SQL, mais XSS est plus délicat. Vous devriez preg_match, stip_tags ou htmlentities si possible!

1
Abeon

La meilleure méthode actuelle pour empêcher XSS dans une application PHP est HTML Purifier (http://htmlpurifier.org/). Un inconvénient mineur est que c'est une bibliothèque assez grande et qu'il vaut mieux l'utiliser avec un cache de code op comme APC. Vous pouvez l'utiliser dans n'importe quel endroit où du contenu non approuvé est affiché à l'écran. Il est beaucoup plus approfondi que htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags, etc.

1
Night Owl

Vous faire tous les cookies de session (ou tous les cookies) que vous utilisez HttpOnly. La plupart des navigateurs masqueront la valeur du cookie de JavaScript dans ce cas. L'utilisateur peut toujours copier manuellement les cookies, mais cela empêche l'accès direct au script. StackOverflow a eu ce problème pendant la version bêta.

Ce n'est pas une solution, juste une autre brique dans le mur

1
basszero

Je trouve que la meilleure façon est d'utiliser une classe qui vous permet de lier votre code afin que vous n'ayez jamais à vous soucier d'échapper manuellement vos données.

0
Darren22

Utilisez une bibliothèque de nettoyage des entrées utilisateur existante pour nettoyer tous entrée utilisateur. À moins d'y consacrer beaucoup d'efforts, sa mise en œuvre vous-même ne fonctionnera jamais aussi bien.

0
dbr