Quelles sont les meilleures pratiques pour éviter les attaques xss sur un site PHP?
J'ai configuré PHP pour que les guillemets magiques soient activés et que les globals s'enregistrent soient désactivés.
je fais de mon mieux pour toujours appeler htmlentities() pour tout ce que je produis qui est dérivé de l'entrée de l'utilisateur.
il m'arrive aussi de saisir ma base de données pour des choses courantes utilisées dans xss attaché tel que...
<script
que dois-je faire d'autre et comment puis-je m'assurer que les choses que j'essaie de faire sont toujours fait.
20 réponses
échapper à l'entrée n'est pas le meilleur que vous pouvez faire pour la prévention XSS réussie. Aussi la sortie doit être échappée. Si vous utilisez Smarty template engine, vous pouvez utiliser le modificateur |escape:'htmlall'
pour convertir tous les caractères sensibles en entités HTML (j'utilise le propre modificateur |e
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 de l'utilisateur non modifié (aucun HTML s'échappe sur l'entrée, seulement DB-aware s'échappe fait via AOP prepared statements)
- échapper à la sortie, selon le format de sortie que vous utilisez (par exemple, HTML et JSON besoin de différents échapper règles)
je suis d'avis qu'on ne doit rien échapper pendant l'entrée, seulement sur la sortie. Puisque (la plupart du temps) vous ne pouvez pas supposer que vous savez où ces données vont. Par exemple, si vous avez une forme qui prend des données qui apparaissent plus tard dans un courriel que vous envoyez, vous avez besoin d'échapper différent (autrement un utilisateur malveillant pourrait réécrire vos en-têtes de courriel).
en d'autres termes, vous ne pouvez vous échapper qu'au tout dernier moment où les données sont "quitter" votre application:
- article de la liste
- Écrire dans un fichier XML, escape for XML
- Écrire DB, escape (pour le SGBD)
- Écrire un e-mail, s'échapper pour des e-mails
- etc
Pour faire court:
- vous ne savez pas où vont vos données Les données
- pourraient en fait se retrouver à plus d'un endroit, nécessitant différentes mécanisme d'échappement mais pas les deux
- données échappées pour la mauvaise cible n'est vraiment pas agréable. (P. ex. obtenez 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 vous avez besoin de le désamorcer à nouveau, etc).
PS: je suis d'accord avec le Conseil de ne pas utiliser magic_quotes, ce sont des pures diaboliques!
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 le délègue personnellement au cadre actuel que j'utilise (déclencheur de Code par exemple). Bien que pas parfait, il pourrait attraper plus que ma main fait routines jamais.
C'est une grande question.
tout d'abord, n'échappez pas au texte à l'entrée, sauf pour le rendre sûr pour le stockage (comme être mis dans une base de données). La raison pour cela est que vous voulez garder ce qui a été input de sorte que vous pouvez le présenter contextuellement de différentes façons et lieux. Faire des changements ici peut compromettre votre présentation ultérieure.
lorsque vous allez présenter vos données filtrer ce qui ne devrait pas être là. Par exemple, s'il n'y a pas de raison pour javascript doit être là le rechercher et de le supprimer. Une façon facile 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 htmlentities pensé ou htmlspecialchars pour changer ce qui est là en caractères ascii. Faites ceci basé sur le contexte et ce que vous voulez sortir.
je suggère aussi d'éteindre les guillemets magiques. Il a été supprimé de PHP 6 et est considéré comme une mauvaise pratique à utiliser. Détails à http://us3.php.net/magic_quotes
pour plus de détails, voir http://ha.ckers.org/xss.html
Ce n'est pas une réponse complète, mais, espérons-le, assez pour vous aider à obtenir commencé.
rikh écrit:
je fais de mon mieux pour toujours appeler htmlentities() pour tout ce que je produis qui est dérivé de l'entrée de l'utilisateur.
Voir Joel, son essai sur Rendre le Code Regarde Mal pour aider à cette
je m'appuie sur PHPTAL pour que.
contrairement à Smarty et plain PHP, il échappe à toute sortie par défaut. C'est une grande victoire pour la sécurité, parce que votre site ne deviendra pas vurnelable si vous oubliez htmlspecialchars()
ou |escape
quelque part.
XSS est une attaque spécifique au HTML, donc la sortie HTML est le bon endroit pour l'empêcher. Vous ne devriez pas essayer de pré-filtrage des données dans la base de données, parce que vous pourriez avoir besoin de produire des données à un autre médium qui n'accepte pas HTML, mais qui a ses propres risques.
la bibliothèque de modèles. ou du moins, c'est ce que les bibliothèques de modèles devraient faire. Pour empêcher XSS tous sortie doit être encodé. Ce n'est pas la tâche de la logique d'application / Commande principale, elle doit être gérée uniquement par les méthodes de sortie.
si vous sprinkle htmlentities() thorughout votre code, la conception globale est erronée. Et comme vous le suggérez, vous pourriez manquer une ou deux taches. C'est pourquoi la seule solution est encodage html rigoureux - > lorsque les variables de sortie sont inscrites 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 préoccupent pas de l'encodage de sortie, ou de la localisation, ou de la validation html, ou quoi que ce soit d'important. Peut-être que quelqu'un d'autre connaît une bibliothèque de templates appropriée pour php?
échapper à toutes les entrées utilisateur est suffisant pour la plupart des sites. Assurez-vous également que les identifiants de session ne finissent pas dans L'URL afin qu'ils ne puissent pas être volés du lien Referer
vers un autre site. En outre, si vous permettez à vos utilisateurs de soumettre des liens, assurez-vous qu'aucun lien de protocole javascript:
n'est autorisé; ceux-ci exécuteraient un script dès que l'utilisateur clique sur le lien.
si vous êtes préoccupé par les attaques XSS, encoder vos chaînes de production 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.
lire plus: de la Désinfection des données de l'utilisateur: Comment et où le faire
personnellement, je désactiverais magic_quotes. Dans PHP5+ il est désactivé par défaut et il est préférable de 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 de l'utilisateur que vous filtrez, dictera quoi faire ensuite, par exemple si ce n'est que du texte, par exemple un nom, puis strip_tags(trim(stripslashes()));
il ou pour vérifier les plages utiliser des expressions régulières.
si vous attendez une certaine gamme de valeurs, créez un tableau des valeurs valides et n'autorisez ces valeurs qu'à travers ( in_array($userData, array(...))
).
si vous vérifiez des nombres utilisez is_numeric pour forcer des nombres entiers ou cast à un type spécifique, qui devrait empêcher les gens essayant d'envoyer des chaînes à la place.
si vous avez PHP5.2 + envisagez ensuite de regarder filter () et de faire usage de cette extension qui peut filtrer divers types de données, y compris les adresses e-mail. Documentation n'est pas particulièrement bonne, mais s'améliore.
si vous devez gérer HTML alors vous devriez considérer quelque chose comme filtre D'entrée PHP ou Purificateur HTML . Le purificateur HTML valide également le HTML pour sa conformité. Je ne suis pas sûr que le filtre D'entrée soit encore en cours de développement. Les deux vous permettront de définir un ensemble d'étiquettes qui peuvent être utilisées et quels attributs sont autorisés.
quoi que vous décidiez, toujours rappelez - vous, ne faites jamais confiance à quoi que ce soit venant dans votre script PHP d'un utilisateur (y compris vous-même!).
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îne de caractères.
filtrer les entrées est toujours une bonne idée pour n'importe quelle application.
échapper à votre sortie en utilisant htmlentities () et les amis devraient fonctionner aussi longtemps qu'il est utilisé correctement, mais c'est L'équivalent HTML de créer une requête SQL en concaténant des chaînes avec mysql_real_escape_string($var) - il 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, et ensuite d'utiliser une bibliothèque (comme libxml) pour gérer la sérialisation vers XHTML/HTML/etc. Bien sûr, nous sommes très loin de celui d'être populaire et assez vite, mais en attendant, nous devons construire nos documents HTML via opérations à la corde, et c'est intrinsèquement plus risqué.
je trouve que l'utilisation de cette fonction Aide à éliminer un grand nombre d'attaques xss possibles: http://www.codebelay.com/killxss.phps
"Magic quotes" est un palliatif remède pour certaines des pires failles XSS qui fonctionne par échapper à tout à l'entrée, quelque chose qui ne va pas, par conception. Le seul cas où l'on voudrait l'utiliser est quand vous devez absolument utiliser une application PHP existante connue pour être écrite négligemment en ce qui concerne XSS. (Dans ce cas, vous êtes dans un sérieux problème, même avec des "guillemets magiques". Lors du développement de votre propre application, vous devriez désactiver "magic quotes" et suivre les pratiques XSS-safe à la place.
XSS, un cross site scripting vulnerability, se produit lorsqu'une application comprend des chaînes à partir de sources externes (la saisie de l'utilisateur, récupérées sur d'autres sites web, etc) dans son [X]HTML, CSS, ECMAscript ou autre navigateur-sortie interprétée sans s'échapper, en espérant que les caractères spéciaux comme des moins-que ([X]HTML), les guillemets simples ou doubles (ECMAscript) n'apparaît jamais. La bonne solution est de toujours échapper aux chaînes selon les règles du langage de sortie: en utilisant les entités dans [X]HTML, les barres obliques inverses dans ECMAscript etc.
parce qu'il peut être difficile de garder une trace de ce qui n'est pas fiable 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 un langage comme HTML. Certains environnements de programmation le rendent plus facile en introduisant plusieurs types de chaînes incompatibles: "string "(texte normal)," HTML string " (HTML markup) et ainsi de suite. De cette façon, une conversion implicite directe de "string"" "HTML string" serait impossible, et la seule façon qu'une chaîne de caractères puisse devenir un markup HTML est de la passer à travers une fonction d'échappement.
"Register globals", bien que invalidant, c'est certainement une bonne idée, traite d'un problème complètement différent de XSS.
faites de vous des cookies de session (ou tous les cookies) que vous utilisez HttpOnly. Dans ce cas, la plupart des navigateurs masquent la valeur du cookie de JavaScript. L'utilisateur peut encore copier manuellement les cookies, mais cela empêche l'accès direct au script. StackOverflow avait ce problème pendant la bêta.
Ce n'est pas une solution, juste une autre brique dans le mur
- Ne faites pas confiance à la saisie de l'utilisateur
- Échapper à tout texte libre sortie
- N'utilisez pas magic_quotes; voyez s'il y a une variante DBMS-specfic, ou utilisez PDO
- envisager D'utiliser des cookies HTTP uniquement lorsque cela est possible pour éviter qu'un script malveillant puisse détourner une session
vous devriez au moins valider toutes les données entrant dans la base de données. Et essayez de valider toutes les données sortant de 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!
la meilleure méthode actuelle pour prévenir XSS dans une application PHP est Purifier HTML (http://htmlpurifier.org/). Un inconvénient mineur est qu'il s'agit d'une bibliothèque assez grande et qu'il est préférable de l'utiliser avec un cache de code op comme APC. Vous l'utiliserez dans n'importe quel endroit où du contenu non fiable est envoyé à l'écran. Il est beaucoup plus complet que htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags, etc.
utiliser une bibliothèque existante d'assainissement des entrées-utilisateurs pour nettoyer toutes les entrées-utilisateurs . À moins que vous ne mettiez un lot d'effort en elle, la mettre en œuvre vous-même ne fonctionnera jamais aussi bien.
je trouve que le meilleur moyen 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.
il est difficile de mettre en œuvre une injection sql/XSS préventive sur un site qui ne cause pas de fausses alarmes. Dans un CMS, l'utilisateur final pourrait vouloir utiliser <script>
ou <object>
qui renvoie à des éléments d'un autre site.
je recommande à tous les utilisateurs d'Installer FireFox avec NoScript ; -)