miércoles, 25 de septiembre de 2013

Política del mismo origen (Same Origin Policy)

La política del mismo origen es una importante regla de seguridad que implementan todos los navegadores modernos. Su propósito es impedir que un script procedente de un sitio externo pueda acceder al DOM, datos y cookies de otra página y que pueda utilizar AJAX para realizar peticiones utilizando las cookies y credenciales que el usuario tiene activas (bancos, tiendas, correo, etc).

En otras palabras, se trata de que el navegador mantenga una separación estricta entre diferente páginas/aplicaciones. De esta forma una página cargada en un iframe o en otra pestaña del navegador no puede acceder a tu sesión de Amazon o del banco que tienes abierta en otra pestaña. También se descartan las peticiones AJAX a un origen diferente.

¿Que se considera un origen distinto?

En principio imaginamos un origen distinto como un dominio diferente. Esto es correcto, pero la definición es mucho más amplia. El origen también se considera diferente si cambia el protocolo (de http a https, por ejemplo) o el puerto desde el que se sirven los recursos:

En la siguiente tabla (de wikipedia.com) podemos ver con que orígenes se permite la comunicación si nuestra página original viene desde "http://www.example.com/dir/page.html":

URL Resultado Explicación
http://www.example.com/dir/page2.html Permitido Mismo protocolo y servidor
http://www.example.com/dir2/other.html Permitido Mismo protocolo y servidor
http://username:password@www.example.com/dir2/other.html Permitido Mismo protocolo y servidor
http://www.example.com:81/dir/other.html No Permitido Mismo protocolo y servidor pero diferente puerto
https://www.example.com/dir/other.html No Permitido Diferente protocolo
http://en.example.com/dir/other.html No Permitido Diferente servidor
http://example.com/dir/other.html No Permitido Diferente servidor
http://v2.www.example.com/dir/other.html No Permitido Diferente servidor
http://www.example.com:80/dir/other.html Evitar Puerto por defecto indicado. Depende de la implementación del navegador

¿De qué me protege la Política del mismo origen?

El objetivo es proteger al usuario que está viendo una página en su ordenador, con su navegador, de scripts maliciosos que intenten acceder a sus datos o a otros servidores utilizando sus cookies/credenciales. Si los navegadores no implementaran la SOP (Same Origin Policy) podría darse habitualmente el siguiente problema:

  • Inocencio entra en la página de su banco "misEurillos.com".
  • Inocencio abre otra pestaña para entrar en una tienda online a comprar unos caramelos para la tos: "tengoDeTodo.com".
  • La página de la tienda "tengoDeTodo.com" tiene código JavaScript para intentar robar datos de todos los clientes que entran. Mediante AJAX, hace peticiones a varios bancos conocidos (incluido misEurillos.com).
  • El banco responde con los datos de Inocencio porque la petición AJAX incluye automáticamente las cookies/credenciales que Inocencio tiene aún activas por tener sesión abierta en su banco.
  • El script de la página "tengoDeTodo.com" recibe los datos del banco y se los envía a Malone para realizar sus fechorías.

La política del mismo origen impide a los scripts externos acceder a información de la página y hacer peticiones AJAX a servidores diferentes. En este caso el script no podría enviar las peticiones AJAX a los bancos (son origenes diferentes a "tengoDeTodo.com") ni tendría acceso a las cookies o datos de las otras páginas que Inocencio está viendo.

Lo mismo es válido para el correo: si tenemos una sesión de correo abierta en una pestaña, otra página podría intentar, con sus scripts, acceder a datos de la nuestra o acceder directamente al servidor de correo para obtener nuestra información. Las cookies se envia con la petición AJAX a www.miCorreo.com, por lo que quedaremos identificados como el usuario original.

No todas las interacciones cross-site están prohibidas

Pedir recursos de un dominio diferente es algo habitual en las aplicaciones modernas y no siempre entraña peligro. Muchas páginas web cargan imágenes o contenido multimedia desde un origen diferente. Las restricciones se aplican principalmente a las peticiones que se hacen dinámicamente desde un script ( AJAX mediante XMLHttpRequest ) y a la interacción entre diferentes páginas cargadas en el navegador.

No se plantean las mismas restricciones para todos los casos de comunicación. Un script que se carga mediante la etiqueta <script> tiene acceso sin límites a toda nuestra aplicación. Una página de un dominio diferente que se pide en una etiqueta <iframe> se mostrará sin problemas, pero se limita su acceso al contenido de la página padre o de otros iframes.

En general no se limita la inclusión de contenido embebido mediante etiquetas HTML. Podemos incluir recursos cross-site de diferente tipo:

  • Código javascript con <script src="..."></script>
  • CSS con <link rel="stylesheet" href="...">
  • Imágenes con <img>
  • ficheros multimedia con <video> o <audio>
  • plug-ins con <object>, <embed> o <applet>
  • fonts con @font-face
  • cualquier contenido con <iframe>

La diferencia principal con las peticiones AJAX es que ninguna de las peticiones de la lista anterior permite leer directamente la respuesta. Si estamos en la página del banco, con sesión abierta, y enviamos una petición AJAX, recibiremos los datos bancarios (probablemente en JSON o XML). El script del banco recibe la respuesta y puede leerla. Las respuestas de las peticiones anteriores las interpreta directamente el navegador, no tenemos acceso a ellas ( hay alguna forma de conseguirlo como veremos a continuación, pero tiene sus limitaciones).

¿Por qué <SCRIPT> sí y AJAX no?

El hecho de que se pueda incluir código mediante la etiqueta <script> sin ninguna restricción resulta llamativo. Podemos cargar sin ningún problema las librerias que necesitamos desde un dominio diferente al nuestro, por ejemplo:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

La línea anterior cargará jQuery desde los servidores de Google, sin ninguna limitación. Podemos utilizar los métodos de jQuery para acceder al DOM y a nuestros datos.

El código que se incluye de esta manera queda embebido en nuestra página, el origen de estos ficheros JavaScript queda definido por el origen de la página HTML que los incluye.

Hay algunas diferencias importantes entre una petición con <script> y otra utilizando XMLHttpRequest que hacen la segunda mucho más insegura:

  • La etiqueta <script> no permite leer la información que llega, todo el código que se incluye se ejecuta inmediatamente en el contexto global ( con AJAX la respuesta se recibe como un string y es la aplicación la 'lee' el contenido y decide que hacer con la información).
  • Sólamente se pueden enviar peticiónes HTTP GET, no se puede elegir POST, PUT, DELETE, HEAD, etc.
  • No se pueden modificar las cabeceras que se envian (no se pueden incluir credenciales de seguridad HTTP AUTH).
  • No se puede acceder a la respuesta: cabeceras, código, información, etc. (con AJAX se puede acceder a las cabeceras)

<script> se utiliza a veces para conseguir una comunicación cross-site similar a AJAX, inyectandola mediante javascript en el documento cargado. Esto se conoce como JSONP. De esta manera sí se puede leer información enviada en la respuesta, pero hay una puntualización importante: la implementación de JSONP requiere que tanto el cliente como el servidor utilizen un protocolo especial. Es decir, sólo se pueden leer datos de un servidor que los exponga mediante JSONP, aceptando de esta manera el acceso público a ese recurso desde cualquier origen.

JSONP requiere que tanto el cliente como el servidor utilizen un protocolo especial. Es decir, sólo se pueden leer datos de un servidor que los exponga mediante JSONP, aceptando de esta manera el acceso público a ese recurso desde cualquier origen.

Aún así es importante que sólo se realicen peticiones a servidores propios o sobre los que exista una total confianza, porque, como comentamos antes, el script se ejecuta inmediatamente en el contexto global de la aplicación. La respuesta puede devolver una llamada a una función, tal como se espera, y despues otro código malicioso que se ejecutará también ciegamente.

Fuentes:
W3C - Same-Origin Policy
Política del mismo origen, Cross-Site Scripting (web)
MDN: Same-origin policy
IT Security: Why is the same origin policy so important?
Principles of the Same-Origin Policy draft-abarth-principles-of-origin-00
stackoverflow: Why are cross domain ajax requests labelled as a security risk
StackOverflow: Why do browser APIs restrict cross domain requests
StackOverflow: Why the cross domain ajax is a security concern

No hay comentarios:

Publicar un comentario