2008-08-19 50 views
51

¿Cuál es la mejor manera de desinfectar las entradas del usuario para una aplicación web basada en Python? ¿Hay una función única para eliminar los caracteres HTML y otras combinaciones de caracteres necesarios para evitar un ataque de inyección de SQL XSS?Desinfección de entrada de usuario utilizando Python

+9

no se le debe intentar arreglar la inyección de SQL desinfectando ¡Si el API de la base de datos se usa correctamente, no hay posibilidad de inyección SQL. –

+2

'... si se utiliza la API de la base de datos correctamente no hay posibilidad de inyección SQL'. De forma adecuada, ¿te refieres a utilizar consultas parametrizadas? ¿Eso te cubre al 100%? – Medorator

+2

@buffer, sé que su comentario es antiguo, pero si desea que otras personas, además de OP, vean sus comentarios, debe llamarlos con un símbolo \ @. – user1717828

Respuesta

0

Si está utilizando un marco como django, el marco puede hacer esto fácilmente con filtros estándar. De hecho, estoy bastante seguro de que django lo hace automáticamente a menos que le digas que no lo haga.

De lo contrario, recomendaría usar algún tipo de validación de expresiones regulares antes de aceptar entradas de formularios. No creo que haya una solución mágica para su problema, pero al usar el módulo re, debería poder construir lo que necesita.

6

Jeff Atwood mismo describió cómo StackOverflow.com desinfecta la entrada del usuario (en términos de lenguaje no-específico) en el blog de desbordamiento de pila: http://blog.stackoverflow.com/2008/06/safe-html-and-xss/

Sin embargo, como señala Justin, si utiliza las plantillas de Django o algo similar entonces probablemente desinfectarán tu salida de HTML de todos modos.

La inyección de SQL tampoco debería ser una preocupación. Todas las bibliotecas de base de datos de Python (MySQLdb, cx_Oracle, etc.) siempre desinfectan los parámetros que pasa. Estas bibliotecas son utilizadas por todos los mapeadores relacionales de objetos de Python (como los modelos de Django), por lo que no tiene que preocuparse por el saneamiento allí tampoco.

24

Aquí hay un fragmento que eliminará todas las etiquetas que no estén en la lista blanca, y todos los atributos de etiquetas que no estén en la lista blanca attribues (para que no pueda usar onclick).

que es una versión modificada de http://www.djangosnippets.org/snippets/205/, con la expresión regular en los valores de atributo para evitar que la gente use href="javascript:...", y otros casos descritos en http://ha.ckers.org/xss.html.
(por ejemplo <a href="ja&#x09;vascript:alert('hi')"> o <a href="ja vascript:alert('hi')">, etc.)

Como se puede ver, se utiliza la (impresionante) BeautifulSoup biblioteca.

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') 

Como los otros críticos han dicho, casi todas las bibliotecas db Python cuidar de inyección de SQL, por lo que este debe más o menos cubierta ti.

+2

He votado a favor, pero ahora no estoy tan seguro. No creo que esto proteja a los usuarios de IE de los ataques src = "vbscript: msgbox ('xss')". –

+0

Puede agregar fácilmente eso con otra expresión regular para vbscript: como la de javascript: – tghw

+3

Protección VBScript agregada. – tghw

4

no hago el desarrollo web mucho más tiempo, pero cuando lo hice, hice algo así:

Cuando se supone ningún análisis a suceder, por lo general sólo escapar de los datos para no interferir con la base de datos cuando lo almaceno, y escapo todo lo que leo de la base de datos para no interferir con html cuando lo visualizo (cgi.escape() en python).

Lo más probable es que, si alguien intente ingresar caracteres html o cosas así, en realidad quisieran que se muestre como texto de todos modos. Si no lo hicieron, bien difícil :)

En resumen, siempre escapa lo que puede afectar el objetivo actual para los datos.

Cuando necesité algún tipo de análisis (marcado o lo que sea), generalmente trataba de mantener ese idioma en un conjunto que no se cruza con html, así podía almacenarlo adecuadamente escapado (después de validar los errores de sintaxis) y analizarlo html cuando se visualiza sin tener que preocuparse por los datos que el usuario pone interfiere con su html.

Ver también Escaping HTML

12

La mejor manera de prevenir XSS no es tratar de filtrar todo, pero en lugar de simplemente hacer HTML Entidad codificación. Por ejemplo, gire automáticamente < en & lt ;. Esta es la solución ideal, suponiendo que no necesita aceptar ninguna entrada html (fuera de las áreas de foro/comentario donde se usa como marcado, debería ser bastante raro tener que aceptar HTML); hay tantas permutaciones a través de codificaciones alternativas que cualquier cosa menos una lista blanca ultra-restrictiva (a-z, A-Z, 0-9 por ejemplo) va a dejar pasar algo.

Inyección SQL, contrariamente a otra opinión, todavía es posible, si solo está construyendo una cadena de consulta. Por ejemplo, si está concatenando un parámetro entrante en una cadena de consulta, tendrá inyección de SQL. La mejor forma de protegerse contra esto tampoco es filtrar, sino usar religiosamente consultas parametrizadas y NUNCA concatenar la entrada del usuario.

Esto no quiere decir que el filtrado no sea aún una buena práctica, pero en términos de inyección SQL y XSS, estará mucho más protegido si utiliza religiosamente Parameterize Queries y HTML Entity Encoding.

+0

Esto no es correcto en muchos casos. Consulte las notas de OSWAP sobre "¿Por qué no puedo solo codificar la entidad HTML con datos que no son de confianza?" https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet – Purrell

19

Editar: bleach es un envoltorio alrededor de html5lib que hace que sea aún más fácil de usar como desinfectante basado en una lista blanca.

html5lib viene con un desinfectante de HTML basado en la lista blanca - es fácil de subclase para restringir las etiquetas y atributos usuarios están autorizados a utilizar en su sitio, y que incluso los intentos de desinfectar CSS si se va a permitir el uso de la style atributo.

Aquí está ahora estoy usando la función sanitize_html utilidad de mi desbordamiento de pila clon:

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

he tirado todos los ataques que figuran en ha.ckers.org's XSS Cheatsheet (que son hábilmente available in XML format en ello después de realizar Markdown a Conversión de HTML usando python-markdown2 y parece haberse mantenido bien

El componente del editor de WMD que Stackoverflow usa actualmente es un problema, de hecho, tuve que deshabilitar JavaScript para probar el XS S ataques de Cheatsheet, ya que pegarlos a todos en WMD terminó dándome cuadros de alerta y borrando la página.

2

Para desinfectar una entrada de cadena que desee almacenar en la base de datos (por ejemplo, un nombre de cliente) necesita escaparse o simplemente eliminar cualquier comilla (', ") de esta. puede suceder si usted está montando una consulta SQL de cadenas pasadas por el usuario

por ejemplo (si es aceptable para eliminar las citas por completo):.

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

Er ... no ... Todavía no haría esto. Para todo lo que sea un elemento de datos, use consultas parametrizadas. Para las consultas que no son de datos (creadas dinámicamente), realmente debería estar usando una lista blanca. 'pg_catalog.pg_user' no contiene comillas, pero probablemente tampoco lo desee en sus consultas generadas. En su lugar, haga algo como 'datasetName = datasetName if datasetName en DATASETNAME_WHITELIST else sulk()' – SingleNegationElimination

Cuestiones relacionadas