El libro de Django 1.0

19.3. Cross-Site Scripting (XSS)

El Cross-site scripting (XSS) (Scripting inter-sitio), puede encontrarse en aplicaciones Web que fallan a la hora de escapar en forma correcta contenido provisto por el usuario antes de renderizarlo en HTML. Esto le permite a un atacante insertar HTML arbitrario en tu página Web, normalmente en la forma de etiquetas <script>.

Los atacantes a menudo usan ataques XSS para robar información de cookies y sesiones, o para engañar usuarios y lograr que proporcionen información privada a la persona equivocada (también conocido como phishing).

Este tipo de ataque puede tomar diferentes formas y tiene prácticamente infinitas permutaciones, así que sólo vamos a analizar un ejemplo típico. Consideremos esta simple vista "Hola mundo":

def say_hello(request):
    name = request.GET.get('name', 'world')
    return render_to_response("hello.html", {"name" : name})

Esta vista simplemente lee un nombre desde un parámetro GET y pasa dicho nombre a la plantilla hello.html. Podríamos escribir una plantilla para esta vista de la siguiente manera:

<h1>Hello, {{ name }}!</h1>

De manera que si accediéramos a http://example.com/hello/?name=Jacob, la página renderizada contendría lo siguiente:

<h1>Hello, Jacob!</h1>

Pero atención — ¿qué sucede si accedemos a http://example.com/hello/?name=<i>Jacob</i>? En ese caso obtenemos esto:

<h1>Hello, <i>Jacob</i>!</h1>

Obviamente, un atacante no usará algo tan inofensivo como etiquetas <i>; podría incluir un fragmento completo de HTML que se apropiara de tu página insertando contenido arbitrario. Este tipo de ataques ha sido usado para engañar a usuarios e inducirlos a introducir datos en lo que parece ser el sitio Web de su banco, pero en efecto es un formulario saboteado vía XSS que envía su información bancaria a un atacante.

El problema se complica aun más si almacenas estos datos en la base de datos y luego la visualizas en tu sitio. Por ejemplo, en una oportunidad se encontró que MySpace era vulnerable a un ataque XSS de esta naturaleza. Un usuario había insertado JavaScript en su página de perfil, dicho código se agregaba a la lista de amigos de todos los usuarios que visitaran su página de perfil. En unos pocos días llegó a tener millones de amigos.

Ahora, esto podría sonar relativamente inofensivo, pero no olvides que este atacante había logrado que su código — no el código de MySpace — se ejecutara en tu computadora. Esto viola la confianza asumida acerca de que todo el código ubicado en MySpace es realmente escrito por MySpace.

MySpace fue muy afortunado de que este código malicioso no hiciera cosas como borrar automáticamente las cuentas de los usuarios que lo ejecutaran, o cambiar sus contraseñas, o inundar el sitio con spam, o cualquiera de los otros escenarios de pesadilla que esta vulnerabilidad hace posibles.

19.3.1. La solución

La solución es simple: siempre escapa todo el contenido que pudiera haber sido enviado por un usuario. Si simplemente reescribiéramos nuestra plantilla de la siguiente manera:

<h1>Hello, {{ name|escape }}!</h1>

ya no seríamos vulnerables. Debes usar siempre la etiqueta escape (o algo equivalente) cuando visualizas en tu sitio contenido enviado por el usuario.