64 votes

Assainissement de l'entrée utilisateur à l'aide de Python

Quelle est la meilleure façon d'assainir les entrées utilisateur pour une application Web basée sur Python ? Existe-t-il une fonction unique permettant de supprimer les caractères HTML et toute autre combinaison de caractères nécessaire pour éviter une erreur de saisie ? XSS ou une attaque par injection SQL ?

10 votes

Vous ne devriez pas essayer de résoudre le problème de l'injection SQL en nettoyant les données de l'utilisateur ! Si l'API de la base de données est utilisée correctement, il n'y a aucun risque d'injection SQL.

4 votes

... if database API is used properly there is no chance of SQL injection . Par correctement, voulez-vous dire utiliser des requêtes paramétrées ? Cela vous couvre-t-il à 100% ?

2 votes

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

29voto

tghw Points 14244

Voici un extrait qui supprimera toutes les balises qui ne figurent pas sur la liste blanche, ainsi que tous les attributs de balises qui ne figurent pas sur la liste blanche des attributs (vous ne pouvez donc pas utiliser la fonction onclick ).

Il s'agit d'une version modifiée de http://www.djangosnippets.org/snippets/205/ avec le regex sur les valeurs de l'attribut pour empêcher les gens d'utiliser href="javascript:..." et d'autres cas décrits à l'adresse 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) BelleSoupe bibliothèque.

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 posteurs, pratiquement toutes les bibliothèques de bases de données Python prennent en charge les injections SQL, ce qui devrait vous couvrir.

2 votes

J'ai voté pour, mais maintenant je n'en suis pas si sûr. Je ne pense pas que cela protège les utilisateurs d'IE des attaques src="vbscript:msgbox('xss')".

0 votes

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

1 votes

@tghw, L'exemple de vbscript ici est la raison pour laquelle les solutions de liste blanche sont généralement préférables aux solutions de liste noire. Comment pouvez-vous être sûr que tout ce dont vous avez besoin est sur liste noire ? Avec une liste noire, un nouveau navigateur pourrait sortir la semaine prochaine et être vulnérable parce qu'il supporte un nouveau type de balise script.

23voto

insin Points 19509

Modifier : eau de Javel est une enveloppe autour de html5lib qui facilite encore plus son utilisation en tant qu'assainisseur basé sur une liste blanche.

html5lib est livré avec un désinfectant HTML basé sur une liste blanche - il est facile de le sous-classer pour restreindre les balises et les attributs que les utilisateurs sont autorisés à utiliser sur votre site, et il tente même de désinfecter les CSS si vous autorisez l'utilisation de la balise style attribut.

Voici comment je l'utilise dans mes clones de Stack Overflow. sanitize_html fonction d'utilité :

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

J'ai jeté toutes les attaques listées dans XSS Cheatsheet de ha.ckers.org (qui sont facilement disponible en format XML après avoir effectué la conversion de Markdown en HTML en utilisant python-markdown2 et il semble qu'il ait tenu bon.

Le composant d'édition WMD que Stackoverflow utilise actuellement pose toutefois un problème. J'ai dû désactiver JavaScript afin de tester les attaques XSS Cheatsheet, car en les collant dans WMD, j'obtenais des boîtes d'alerte et la page devenait blanche.

13voto

user17898 Points 111

La meilleure façon d'éviter les XSS n'est pas d'essayer de tout filtrer, mais plutôt de procéder simplement à l'encodage des entités HTML. Par exemple, transformer automatiquement < en <. C'est la solution idéale si vous n'avez pas besoin d'accepter d'entrée HTML (en dehors des forums/commentaires 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.

L'injection SQL, contrairement à ce que l'on pense, est toujours possible, si vous ne faites que construire une chaîne de requête. Par exemple, si vous ne faites que concaténer un paramètre entrant dans une chaîne de requête, vous aurez une injection SQL. La meilleure façon de s'en protéger n'est pas non plus de filtrer, mais plutôt d'utiliser religieusement des requêtes paramétrées et de ne JAMAIS concaténer les entrées utilisateur.

Cela ne veut pas dire que le filtrage n'est pas encore une bonne pratique, mais en termes d'injection SQL et de XSS, vous serez beaucoup plus protégé si vous utilisez religieusement les requêtes paramétrées et le codage d'entités HTML.

1 votes

Cela n'est pas correct dans de nombreux cas. Voir les notes de l'OSWAP sur "Why Can't Just HTML Entity Encode Untrusted Data ?" (Pourquoi ne puis-je pas simplement coder des données non fiables avec une entité HTML ? owasp.org/index.php/

6voto

Eli Courtwright Points 53071

Jeff Atwood a lui-même décrit la manière dont StackOverflow.com aseptise les entrées des utilisateurs (en termes non spécifiques à une langue) sur le blog de Stack Overflow : https://blog.stackoverflow.com/2008/06/safe-html-and-xss/

Toutefois, comme le souligne Justin, si vous utilisez des modèles Django ou quelque chose de similaire, ils aseptisent probablement votre sortie HTML de toute façon.

L'injection SQL ne devrait pas non plus poser de problème. Toutes les bibliothèques de bases de données Python (MySQLdb, cx_Oracle, etc.) aseptisent toujours les paramètres que vous passez. Ces bibliothèques sont utilisées par tous les mappeurs objet-relationnel de Python (comme les modèles de Django), vous n'avez donc pas à vous soucier de l'assainissement là non plus.

4voto

Henrik Gustafsson Points 11755

Je ne fais plus beaucoup de développement web, mais quand je le faisais, je faisais quelque chose comme ça :

Lorsqu'aucune analyse syntaxique n'est censée se produire, je me contente généralement d'échapper les données pour ne pas interférer avec la base de données lorsque je les stocke, et d'échapper tout ce que je lis dans la base de données pour ne pas interférer avec le html lorsque je l'affiche (cgi.escape() en python).

Il y a de fortes chances pour que, si quelqu'un essaie de saisir des caractères html ou autres, il veuille de toute façon les afficher sous forme de texte. Si ce n'est pas le cas, tant pis :)

En bref, il faut toujours échapper à ce qui peut affecter l'objectif actuel des données.

Lorsque j'avais besoin d'une analyse syntaxique (balisage ou autre), j'essayais généralement de garder ce langage dans un ensemble sans intersection avec le html, afin de pouvoir le stocker de manière appropriée (après avoir validé les erreurs de syntaxe) et l'analyser en html lors de l'affichage sans avoir à se soucier des données que l'utilisateur y a insérées et qui interfèrent avec le html.

Voir aussi Échapper au HTML

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X