Advertisement
  1. Code
  2. HTML5

HTML5 Nivel Experto: Seguridad Web

Scroll to top
Read Time: 10 min
This post is part of a series called HTML5 Mastery Class.
HTML5 Mastery: The Browsing Context
HTML5 Mastery: DOM Mutations

Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)

HMTL5 Mastery series imageHMTL5 Mastery series imageHMTL5 Mastery series image

La seguridad es un tema que vuelve de vez en cuando. No es un problema desde el principio, pero una vez que pasa algo malo generalmente es considerada la culpable. El software es algo complejo, la programación que realizan los humanos en las máquinas dista mucho de ser perfecta, y además el usuario podría no seguir las mejores prácticas. ces, ¿cómo podemos crear un sistema seguro?

La web es uno de los lugares más inseguros posibles. Los ordenadores con riesgos potenciales de seguridad están conectados unos a otros. Los servidores pueden recibir datos arbitrarios. Los clientes ejecutan código de fuentes desconocidas. Mientras no podamos controlar la seguridad de los servidores, tenemos que hacer algo para proteger a los clientes. Aunque JavaScript podría ser considerado un lenguaje de programación seguro, el código para cualquier plugin ActiveX, Flash o Silverligjht definitivamente no lo es. Además, aunque JavaScript sí mismo esté aislado, podría utilizarse de tal manera que el usuario desencadenará acciones inseguras.

En este tutorial veremos el modelo de seguridad web en acción. Revisaremos las mejores prácticas y pautas generales para crear aplicaciones web seguras. Aprenderemos de qué tratan las políticas sobre compartir de recursos de procedencias diversas y cómo podemos controlarlo. Por último hablaremos también sobre la manera de aislar (externamente) contenido.

Pautas de Seguridad

Una de las pautas más importantes no tiene que ver directamente con HTML: ¡Usa HTTPS! La relación con HTML descansa por supuesto en la distribución de tus documentos de hipertexto. Sin embargo tenemos que darnos cuenta de que el uso de HTTPS para el transporte de nuestro documento y el empleo de HTTPS para nuestros recursos son dos cosas diferentes. Es definitivamente necesario comprobar si todos los recursos contenidos emplean verdaderamente el protocolo https://.

Otra pauta importante está relacionada con el contenido definido por ele usuario. Una vez que hayamos permitido que los usuarios introduzcan datos en un formulario, necesitamos tener cuidado. No sólo debemos asegurarnos de que el servidor web está protegido contra ataques comunes, como inyecciones SQL, también debemos asegurarnos de que los datos almacenados no sean empleados dentro del código ejecutable sin cuidado. Por ejemplo deberíamos eludir las cadenas que no contegan código HTML. El HTML por sí sólo no es malicioso, pero puede desencadenar la ejecución de un script o la obtención de recursos. Una forma de permitir que los usuarios escriban HTML, lo que podría ubicarse en la página de salida sin modificaciones, es crear una lista blanca con ciertas etiquetas y atributos. Los otros elementos serán eludidos.

Nuestro JavaScript debería también minimizar su exposición y confianza en librerías de terceras partes. Por supuesto usamos la expresión  invoca la función inmediatamente (IIFE) para prevenir que el contexto global sea contaminado; no obstante, otro motivo es no filtrar (probablemente) estados internos clave, que podrían después ser modificados por otros scripts deliberadamente o por casualidad.

1
(function () {
2
  // Standard code here.

3
})();

Ciertamente desde nuestro punto de vista es una buena practica confiar en el uso de 'use strict'; y sus beneficios asociados. Sin embargo, restringir el script que se está ejecutando no evita que hagamos uso de APIs con datos potencialmente dañados. las cookies y el contenido de localStorage podrían ser modificados o vistos por el usuario u otros programas dependiendo de las condiciones sobre las que no tenemos influencia.  Por tanto siempre deberíamos implementar algunas comprobaciones de higiene, que nos den una pista para detectar los posibles defectos de integridad tan pronto sea posible.

Por último deberíamos asegurarnos de usar sólo recursos de terceros de confianza. Usar scripts de otros servidores dentro de nuestra web hace que sea posible mutar la página o abrir una brecha en la privacidad de nuestros usuarios.

Compartir Recursos Cross-Origin

El concepto sobre compartir recursos de distintas fuentes (CORS) es sencillo. El navegador no permite la incrustación de recursos especiales procedentes de diferentes orígenes a menos que nosotros los permitamos de forma explícita. Recursos especiales podrían ser, p. ej., las fuentes web o cualquier solicitud realizada vía XMLHttpRequest. Las solicitudes AJAX de diferentes orígenes están prohibidas de forma predeterminada debido a su capacidad para ejecutar solicitudes avanzadas que introducen muchos problemas programados de seguridad.

El origen o la fuente es definido básicamente a través del protocolo, el alojamiento o la combinación de puertos. Por lo tanto https://a.com es diferente de https://a.com, que es diferente de https://a.com:8080. Todos son diferentes a http://b.com.

A los clientes se les puede permitir el uso de recursos mediante la inclusión de un cierto header en la respuesta.  El navegador entonces determina si la actual web tiene permitido el uso del recurso o no. El origen está normalmente determinado a través del dominio de la actual web.

Echemos un vistazo a un ejemplo ilustrativo. El lo que viene ahora asumimos que nuestra página está localizada en foo.com. Solicitamos datos JSON de a una página alojada en bar.com. Para la solicitud JSON usamos XMLHttpRequest tal y como se muestra más abajo.

1
var xhr = new XMLHttpRequest();
2
xhr.open('GET', 'https://bar.com/users');
3
xhr.addEventListener('load', function (ev) {
4
	if (xhr.status === 200) {
5
		var result = JSON.parse(xhr.responseText);
6
		// ...

7
	}
8
}, false);
9
xhr.send();

El navegador ya anticipa la posibilidad de una respuesta habilitada CORS añadiendo el header Origin a la solicitud:

1
Origin: http://foo.com

Ahora el servidor tiene que proporcionar la respuesta correcta. No sólo queremos que el JSON correcto sea transportado, sino lo que es aún más importante, requerimos headers CORS específicos. Es posible usar wildcards. Por ejemplo, en el ejemplo siguiente, se otorgará derecho a utilizar el recurso solicitado para cualquier solicitud.

1
Access-Control-Allow-Origin: *

CORS puede utilizarse también como alternativa a la solución JSONP. JSONP usa scripts para hacer solicitudes AJAX de diferentes orígenes dando como resultado respuestas JSON. Con anterioridad a CORS, las solicitudes a diferentes dominios estaban prohibidas en general, pero la inclusión de scripts de diferentes dominios era aceptada. En la mayoría de APIs una respuesta JSONP era provocada por proporcionando un parámetro de consulta especial, nombrando la función de devolución de llamada.

Imagina que la llamada a http://bar.com/api proporciona el siguiente resultado JSON:

1
{ "name": "example", "factor": 5, "active": true }

La llamada JSONP a, p. ej., http://bar.com/api?jsonp=setResult nos dará:

1
setResult({ "name": "example", "factor": 5, "active": true });

Desde que el resultado de JSONP es sólo detectado por el elemento <script>, el método de solicitud GET está ya implícito. No hay posibilidad de usar nada diferente. CORS nos proporciona mucha más libertad es esta área, por ejemplo podríamos también determinar otros parámetros. Todo está habilitado permitiéndonos usar libremente el objeto XMLHttpRequest estandarizado.

Una solución ideal con sólo una alternativa a JSONP para navegadores antiguos, mientras que adopta CORS para los más modernos. Esto evitará muchos problemas de cross-site scripting (XSS) procedentes de sitios externos comprometidos. Incrustar scripts de páginas externas ha sido siempre un empresa arriesgado. Una mejor alternativa hubiese sido el redireccionamiento de la solicitud JSON desde nuestro servidor al equipo de destino. De esta forma hablaríamos con nuestro servidor (de confianza), el cual obtendría la respuesta del destinatario, evaluaría su estado y devolvería el resultado (válido).

Banderas de Aislamiento

Todo document viene con su propia window. El acceso a esta window se hace mediante el uso de proxys desde la window actual del contexto de navegación, la cual nos conduce a la ficha que vemos. El contexto de navegación se crea con varias opciones, por ejemplo la del contexto del padre, la del creador y la de la página inicial. Junto a estas opciones, se establecen indicadores de seguridad. Los indicadores establecieron las capacidades y restricciones del contexto. Realmente es posible prevenir ciertos comportamientos, como la ejecución de scripts o la apertura de nuevas pestañas.

¿Cómo podemos configurar los indicadores de seguridad para un nuevo contexto? Configuramos el contexto por medio de atributos que son asignados a elementos, necesarios para crear un nuevo contexto. En la actualidad sólo el elemento iframe dispone de dicho atributo, aunque los marcos estándar también tendrían cabida en la anterior descripción. Sin embargo, los marcos estándar se consideran obsoletos y por lo tanto no tienen mucha compatibilidad. Aunque el estándar HTML5 los menciona, no se debería hacer uso de ellos más.

Existen un puñado de indicadores disponibles. Los más importantes son:

  • permitir-top-navegación (permite cambiar el marco superior)
  • allow-plugins (permite embedobject,...)
  • allow-same-origin (se pueden acceder a contenidos desde un mismo origen)
  • allow-forms (admite el envío de formularios)
  • allow-popups (los pop-ups / nuevos marcos no serán bloqueados)
  • allow-pointer-lock (habilita la API pointer-lock)
  • allow-scripts (permite la ejecución de scripts)

El <iframe> emplea el atributo sandbox para iniciar el modo de prueba sandbox. Si no se especifica este atributo, todo está permitido tal como lo conocemos. Con este atributo, todo está prohibido. Por lo tanto, los indicadores previamente establecidos permiten ciertas características.

Echemos un vistazo más de cerca al indicador allow-same-origin. Por defecto, la norma para un iframe es realmente muy laxa. Si no especificamos el atributo sandbox, entonces sólo estará permitido leer las páginas incrustadas pertenecientes al mismo dominio, p. ej., cookies o el almacenamiento local del navegador para dicho dominio. Por supuesto existen también otros riesgos, por ese motivo normalmente queremos proporcionar el atributo sandbox.

La siguiente imagen muestra el comportamiento predeterminado en un diagrama sencillo. Mientras al segundo iframe le está permitido acceder al los contenidos previamente establecidos, a la primera de ellas no. La razón es que pertenecen a un dominio diferente, destacado en amarillo.

IFrame Standard OriginIFrame Standard OriginIFrame Standard Origin

Entonces, ¿cómo cambia esta imagen con el atributo sandbox? El contenido procedente de un dominio diferente todavía está prohibido. Por lo tanto sólo observaremos las posibilidades adicionales para el contenido procedente de un mismo origen. Por defecto, incluso al contenido con un mismo origen se le trata como si viniese de un origen distinto.

IFrame Sandbox OriginIFrame Sandbox OriginIFrame Sandbox Origin

Existen más funciones que pueden ser controladas o establecidas para determinados contextos, pero estas desafortunadamente son transportadas a través de sus propios atributos. Un excelente ejemplo es el atributo allowfullscreen. De nuevo sólo está disponible para un iframe. En principio permite a las aplicaciones abrirse en modo pantalla completa.

Más aún, deberíamos advertir el atributo seamless para un elemento <iframe>. Este atributo habilita la aplicación del estilo del documento padre en el contenido del documento. Es especialmente potente usado junto con el atributo srcdoc, que nos permite proporcionar el origen de un iframe directamente, sin necesidad de hacer solicitudes HTTP o usar datos URI. Con esto podemos admitir con facilidad el contenido de los usuarios sin preocuparnos por la ejecución de scripts.

Aquí abajo tienes un ejemplo sobre como mostrar contenido del usuario en un entorno de sandbox.

1
<iframe sandbox seamless srcdoc="

2
	<div class=comment>

3
		<h3>Example User</h3>

4
		<span class=comment-content>Custom, but <strong>safe</strong>!</span>

5
	</div>

6
"></iframe>

Los iframes con el atributo sandbox pueden utilizarse para muchas tareas. Por ejemplo, si queremos evaluar scripts de forma segura, podríamos enviar el contenido a evaluar a un controlador especial ubicado dentro de un iframe. El controlador llamaría a la función eval. El marco en línea está en un un espacio aislado (sandboxed) sólo para permitir secuencias de comandos, y nada más. No se podrán abrir popups, la navegación no podrá ser usada, y todo nuestro DOM está separado.

La implementación exacta requiere también el envío de mensajes HTML5 entre documentos. Enviamos la solicitud de evaluación con el método postMessage y recibimos la respuesta a través del evento message.

También podemos crear un entorno aislado para partes de la página actual mediante la Directiva de Seguridad de Contenidos (CSP). Esta propiedad se envía normalmente a través de los headers HTTP de la página, pero HTML nos proporciona la habilidad de configurarlo en una etiqueta <meta>.

Un ejemplo de esto tiene el siguiente aspecto. Tenemos que usar el valor adecuado de http-equiv. El contenido son una serie de definiciones específicas para la página.

1
<meta 
2
	http-equiv="Content-Security-Policy" 
3
	content="default-src https://bar.com; child-src 'none'; object-src 'none'"> 

Las diferentes definiciones (llamadas directivas) también aceptan comodines. El propósito y aspecto exactos dependen en gran medida de las directivas empleadas.

Conclusión

La seguridad web es posible, aunque es difícil de alcanzar y depende en gran medida de parámetros externos (con frecuencia difíciles de controlar). Si podemos minimizar estos parámetros externos, como el contenido insertado o los scriptrs, entonces es probable que estemos en "buena forma". La mayoría de los ataques sólo pueden ejecutarse mediante scripts.

Hemos visto que los marcos (en línea) y los hipervínvulos pueden ser ajustados con alertas de sandbox. Nuestros propios recursos sólo deberían ser implementados con CORS en mente.

Referencias

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.