2008-08-19 2 views
51

Quelle est la meilleure façon d'assainir les entrées utilisateur pour une application Web basée sur Python? Y a-t-il une seule fonction pour supprimer les caractères HTML et toute autre combinaison de caractères nécessaires pour empêcher une attaque par injection XSS ou SQL?Désinfection de l'entrée utilisateur à l'aide de Python

+9

vous ne devriez pas tenter de fixer l'injection SQL par désinfectante Si l'API de la base de données est utilisée correctement, il n'y a aucune chance d'injection SQL –

+2

'... si l'API de base de données est utilisée correctement, il n'y a aucune chance d'injection SQL ». Par correctement, voulez-vous dire utiliser des requêtes paramétrées? Cela vous couvre-t-il à 100%? – Medorator

+2

@buffer, je sais que votre commentaire est ancien, mais si vous voulez que d'autres personnes que OP voient vos commentaires, vous devez les appeler avec un symbole \ @. – user1717828

Répondre

0

Si vous utilisez un framework tel que django, le framework peut facilement le faire pour vous en utilisant des filtres standard. En fait, je suis sûr que django le fait automatiquement à moins que vous le lui disiez. Sinon, je recommanderais d'utiliser une sorte de validation regex avant d'accepter les entrées des formulaires. Je ne pense pas qu'il y ait une solution miracle à votre problème, mais en utilisant le module re, vous devriez être capable de construire ce dont vous avez besoin.

6

Jeff Atwood lui-même décrit comment StackOverflow.com aseptise entrée utilisateur (en termes non spécifiques à une langue) sur le blog Stack Overflow: http://blog.stackoverflow.com/2008/06/safe-html-and-xss/

Cependant, comme le souligne Justin sur, si vous utilisez des modèles Django ou quelque chose de similaire alors ils ont probablement désinfecté votre sortie HTML de toute façon.

L'injection SQL ne devrait pas être un problème. Toutes les bibliothèques de bases de données de Python (MySQLdb, cx_Oracle, etc.) nettoient toujours les paramètres que vous passez. Ces bibliothèques sont utilisées par tous les mappeurs relationnels objet de Python (tels que les modèles Django), vous n'avez donc pas besoin de vous soucier de l'assainissement.

24

Voici un extrait qui supprimera toutes les balises ne figurant pas dans la liste blanche et tous les attributs de balises qui ne figurent pas dans la liste blanche des attributions (vous ne pouvez donc pas utiliser onclick).

Il est une version modifiée de http://www.djangosnippets.org/snippets/205/, avec l'expression régulière sur les valeurs d'attribut pour empêcher les gens d'utiliser href="javascript:...", et d'autres cas décrits à http://ha.ckers.org/xss.html.
(par exemple <a href="ja&#x09;vascript:alert('hi')"> ou <a href="ja vascript:alert('hi')">, etc.)

Comme vous pouvez le voir, il utilise le (génial) bibliothèque BeautifulSoup.

import re 
from urlparse import urljoin 
from BeautifulSoup import BeautifulSoup, Comment 

def sanitizeHtml(value, base_url=None): 
    rjs = r'[\s]*(&#x.{1,7})?'.join(list('javascript:')) 
    rvb = r'[\s]*(&#x.{1,7})?'.join(list('vbscript:')) 
    re_scripts = re.compile('(%s)|(%s)' % (rjs, rvb), re.IGNORECASE) 
    validTags = 'p i strong b u a h1 h2 h3 pre br img'.split() 
    validAttrs = 'href src width height'.split() 
    urlAttrs = 'href src'.split() # Attributes which should have a URL 
    soup = BeautifulSoup(value) 
    for comment in soup.findAll(text=lambda text: isinstance(text, Comment)): 
     # Get rid of comments 
     comment.extract() 
    for tag in soup.findAll(True): 
     if tag.name not in validTags: 
      tag.hidden = True 
     attrs = tag.attrs 
     tag.attrs = [] 
     for attr, val in attrs: 
      if attr in validAttrs: 
       val = re_scripts.sub('', val) # Remove scripts (vbs & js) 
       if attr in urlAttrs: 
        val = urljoin(base_url, val) # Calculate the absolute url 
       tag.attrs.append((attr, val)) 

    return soup.renderContents().decode('utf8') 

Comme l'ont dit les autres affiches, à peu près toutes les bibliothèques db Python prendre soin d'injection SQL, cette couverture devrait à peu près vous.

+2

Je l'ai mis à jour, mais maintenant je ne suis pas si sûr. Je ne pense pas que cela protège les utilisateurs IE contre les attaques src = "vbscript: msgbox ('xss')". –

+0

Vous pourriez facilement ajouter cela avec une autre regex pour vbscript: comme celle pour javascript: – tghw

+3

Protection VBScript ajoutée. – tghw

4

Je ne fais pas le développement web beaucoup plus longtemps, mais quand je l'ai fait, je l'ai fait quelque chose comme ceci:

Lorsqu'aucun analyse syntaxique est censé se produire, je me sauve plus souvent que les données pour ne pas interférer avec la base de données quand je le stocke, et que j'échappe à tout ce que je lis de la base de données pour ne pas interférer avec html quand je l'affiche (cgi.escape() en python).

Les chances sont, si quelqu'un a essayé d'entrer des caractères html ou des choses, ils voulaient réellement que cela soit affiché comme texte de toute façon. Si ce n'est pas le cas, bien difficile :)

En bref, toujours échapper ce qui peut affecter la cible actuelle pour les données. Quand j'avais besoin d'un peu d'analyse (balisage ou autre), j'essayais habituellement de garder ce langage dans un ensemble sans intersection avec html afin que je puisse toujours le stocker correctement échappé (après validation pour les erreurs de syntaxe) et l'analyser html lors de l'affichage sans avoir à se soucier des données que l'utilisateur met en interférant avec votre code html.

Voir aussi Escaping HTML

12

La meilleure façon d'éviter XSS est de ne pas essayer de tout filtrer, mais plutôt de faire simplement le codage HTML entité. Par exemple, tournez automatiquement < en & lt ;. C'est la solution idéale en supposant que vous n'avez pas besoin d'accepter une entrée html (en dehors des zones de forum/commentaire où il est utilisé comme balisage, il devrait être assez rare d'avoir besoin d'accepter du HTML); il y a tellement de permutations via des encodages alternatifs que tout sauf une liste blanche ultra-restrictive (a-z, A-Z, 0-9 par exemple) va laisser passer quelque chose.

Injection SQL, contrairement à d'autres avis, est toujours possible, si vous construisez simplement une chaîne de requête. Par exemple, si vous ne faites que concaténer un paramètre entrant sur une chaîne de requête, vous aurez l'injection SQL. La meilleure façon de se protéger contre cela est également de ne pas filtrer, mais plutôt d'utiliser religieusement des requêtes paramétrées et JAMAIS concaténer les entrées des utilisateurs. Cela ne veut pas dire que le filtrage n'est pas toujours une bonne pratique, mais en termes d'injection SQL et XSS, vous serez bien plus protégé si vous utilisez religieusement les requêtes Parameterize et le codage d'entité HTML.

+0

Ce n'est pas correct dans de nombreux cas. Voir les notes OSWAP sur "Pourquoi est-ce que je ne peux pas simplement Entité HTML Encoder des données non fiables?" https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet – Purrell

19

Modifier: bleach est un wrapper autour de html5lib qui le rend encore plus facile à utiliser en tant que désinfectant à base de liste blanche.

html5lib est livré avec un basé whitelist HTML assainissant - il est facile de sous-classe pour limiter les balises et les attributs utilisateurs sont autorisés à utiliser sur votre site, et il essaie même de désinfectez CSS si vous permettant d'utiliser la style attribut.

est ici maintenant je l'utilise dans mon fonction d'utilité de clone Stack Overflow sanitize_html:

http://code.google.com/p/soclone/source/browse/trunk/soclone/utils/html.py

J'ai jeté toutes les attaques énumérées dans ha.ckers.org's XSS Cheatsheet (qui haut la main available in XML format à elle après avoir effectué Markdown à La conversion HTML en utilisant python-markdown2 et il semble avoir tenu bon

Le composant éditeur WMD que Stackoverflow utilise actuellement est un problème, cependant - J'ai dû désactiver JavaScript pour tester le XS S attaques Cheatsheet, comme les coller tous dans WMD a fini par me donner des boîtes d'alerte et de masquer la page.

2

Pour désinfecter une entrée de chaîne que vous souhaitez stocker dans la base de données (par exemple, un nom de client), vous devez soit y échapper, soit supprimer les guillemets (','). peut se produire si vous assemblez une requête SQL de chaînes transmises par l'utilisateur

par exemple (s'il est acceptable de supprimer les citations complètement).

datasetName = datasetName.replace("'","").replace('"',"") 
+0

Euh ... non ... Je ne le ferais toujours pas. Pour tout ce qui est un élément de données, utilisez des requêtes paramétrées. Pour les non-données (requêtes créées dynamiquement), vous devriez vraiment utiliser une liste blanche. 'pg_catalog.pg_user' ne contient pas de guillemets, mais vous ne le souhaitez probablement pas dans vos requêtes générées. Au lieu de cela, faites quelque chose comme 'datasetName = datasetName si datasetName dans DATASETNAME_WHITELIST sinon sulk()' – SingleNegationElimination

Questions connexes