Thursday, August 27, 2020

Algunos Consejos De Seguridad Para Desarrollar Un Frontend Web (Y Son Muchos Los Que Se Necesitan)

El mundo de las aplicaciones web está en constante renovación, se desarrollan nuevos frameworks y herramientas, se implementan nuevos patrones arquitectónicos como los MicroFrontEnds, de los que hemos hablado en un artículo anterior. Además, el usuario está tomando una interacción mayor y más compleja con la parte frontal, esta complejidad puede llegar a suponer una brecha de seguridad si no se tiene el suficiente cuidado al desarrollar los proyectos.

Figura 1: Algunos consejos de seguridad para desarrollar un frontend web
(Y son muchos los que se necesitan)


En este artículo os hablaré de las distintas amenazas que se pueden dar en nuestra estructura frontal y de cómo prevenirlas. Es decir, vamos a ver un resumen de cuáles son las técnicas de Hacking Web Applications desde el punto de vista de los Client-Side Attacks: XSS, CSRF, SSRF, XSPA o SSJS - para lo que os recomiendo que leáis el libro de Enrique Rando - y también contaré algunos consejos para desarrollar FrontEnds de forma segura para evitarlos.

Figura 2: Libro de "Hacking Web Applications: Client-Side Attacks"
de Enrique Rando en la editorial 0xWord.

En primer lugar, para conocer los puntos débiles más comunes que se pueden dar en nuestra aplicación, debemos conocer los tipos de ataques que se realizan sobre estas y como prevenirlos.

Resumen ligero de Client-Side Attacks

- XSS Cross-Site Scripting: Es un vector de ataque dirigido a una aplicación web o página web que puede permitir a un atacante inyectar código sin que este sea validado y así, conseguir acceso a información sensible, secuestro de sesiones de usuario o subyugar la integridad del sistema. Gracias a ataques XSS se pueden hacer ataques de Session Hijacking, ataques de Click-Jacking, Cross-Site Request Forgery, etcétera, todos aprovechándose de la posibilidad de inyectar código que se va a ejecutar en el cliente. Si dejamos de lado los XSS Google-Persistentes, existen tres tipos de XSS.


Figura 3: Conferencia de "Ataques XSS Google Persistentes" por Chema Alonso

- XSS Directo: Es conocido como XSS Persistente, se da en los formularios y se ejecuta cuando un usuario accede a la ruta donde se ha inyectado el código. Estos XSS Persistentes o Stored-XSS son muy peligrosos y aparecen periódicamente en plataformas de eCommerce, CMS, LMS, etcétera, sobre todo en plugins.

Figura 4: Esquema de una ataque XSS Directo

- XSS Indirecto: Es conocido como XXS Reflejado, la inyección de código se da en formularios, URLs o vídeos, entre otros. Su objetivo radica en modificar los valores que la aplicación web utiliza para comunicarse a nivel interno con dos de sus rutas.
Figura 5: Esquema de una ataque XSS Indirecto o XSS Reflejado
 
Evidentemente, para prevenir estos dos tipos de ataques de Cross-Site Scripting, al igual que para prevenir cualquier tipo de ataque de inyección, como son también los ataque de SQL Injection, se debe aplicar un filtro para validar todos los campos que utilicemos como input, ya sean por GET o por POST.  Como dijo Michael Howard en su libro de Writing Secure Code:

"All input is evil until it proves otherwise"

Para evitar estos ataques es importante que tu servidor web también haga uso de los Security Headers para utilizar todas las capacidades de los navegadores de hoy en día en la fortificación contra ataques XSS, para ello hay que configurar:

- X-XSS-Protection
- Content-Type
- X-Content-Type-Options
- X-FrameOptions
- Acces-Control-Allow-Origin

Para verificar las políticas de fortificación de tu web, y cómo están configurados los HTTP Security Headers, puedes usar la web de SecurityHeaders.io que te dará un informe de cómo está de bien configurada tu aplicación web.

- XSS DOM Based: Este tipo de XSS, en vez de darse en la parte HTML se da en el Document Object Model. En los dos tipos anteriores el payload se puede observar en la respuesta de la página o ruta. Sin embargo, en este tipo de XSS el código HTML y la respuesta serán exactamente iguales. El payload solo se podrá observar en tiempo de ejecución o investigando el DOM de la página. 

Figura 6: Esquema de ataque XSS DOM-Based

Para evitar los ataques XSS DOM Based en nuestra aplicación es recomendable utilizar un método de salida adecuado. Es decir, imagina que quieres que el usuario escriba un input en una etiqueta <Div>. En este caso en vez de utilizar innerHTML, utiliza innerText o textContent. De esta forma el usuario puede ejecutar la misma acción, pero evitando una vulnerabilidad XSS DOM Based.

- Ataques DoS/DDoS: Uno de los ataques de XSS, además de los citados en los párrafos anteriores, se basa en la capacidad de forzar al navegador a pedir una determinada URL si somos capaces de inyectar código en la página de respuesta. Esto se puede utilizar para llevar a un cliente con un navegador vulnerable a una web con un Kit de Exploits en un ataque de Watering Hole, o para hacer un ataque de DoS (Denial of Service)

En este último caso el objetivo es dejar sin recursos el servidor para evitar que los usuarios se conecten a este. Funciona sobrecargando el servidor con un gran número de peticiones en intervalos muy pequeños gracias a que muchos clientes le van a pedir recursos pesados de manera involuntaria desde sitios vulnerables a XSS.

Figura 7: Esquema de ataque DDoS. El atacante inyecta el XSS en el servidor web vulnerable y conecta los visitantes a su XSS-Botnet o JavaScript Botnet para hacer un DDoS. 

Estos ataques, cuando se basan en exploits XSS almacenados en sitios de gran cantidad de usuarios a los que se fuerza a pedir recursos pesados en el servidor de la víctima, da como consecuencia ataques DDoS (Distributed Denial of Service). Para el servidor atacado por las peticiones masivas es un problema, y por eso se utilizan soluciones como Cloudflare, AntiDDOS o captchas para proteger los recursos "pesados" para evitar estos ataques. Cada visitante del sitio con el exploit XSS se convierte en un bot de una XSS-Botnet, que funcionan de forma similar a las Javascript Botnets.

Figura 8: Owning bad guys {and mafia} with Javascript Botnets

- Ataques Cross-Site Request Forgery (CSRF): Este ataque se suele utilizar para realizar estafas. Consiste en intentar engañar a la víctima para envíe una solicitud HTTP maliciosa que el cliente no controla. Esto se puede hacer con un simple ataque de Phishing con un e-mail o haciendo un ataque de XSS. En cualquier caso, cuando esto ocurre, el atacante consigue que la víctima haga algo involuntario a ella en una plataforma a la que el atacante no tiene acceso.  Las posibilidades de estos ataques son muchas. Desde crearse un usuario, hasta borrar un contenido, forzar el cierre de sesión en una red social como Facebook o darse permisos desde la sesión de un administrador, o, como hemos visto muchas veces, conseguir votos involuntarios en concursos vulnerables a CSRF.

Figura 9: Esquema de ataque CSRF

La forma de prevenir un ataque CSRF es que la URL solo pueda ser llamada desde una web previa que tiene unos tokens que le autorizan como punto de llamada válido. Es decir, el servidor web protege la URL2 enviándole a la URL1 un token aleatorio Anti-CSRF. Cuando el usuario hace clic en un enlace de la web en la URL1 para navegar a la URL2 debe enviar los tokens AntiCSRF. La URL2 comprueba que son correctos y permite que se ejecute. Como el atacante no puede saber cuáles son los tokens AntiCSRF que genera el servidor web, entonces no puede hacer "a ciegas" que la víctima haga algo mediante una inyección de un exploit XSS o de un e-mail de phishing

Además de todo esto, hay que tener en cuenta que, al forzar una petición HTTP contra un servidor, se podrían enviar cookies asociadas en las peticiones HTTP al nuevo servidor, así que hay que fortificar las cookies para que el acceso solo sea Same-Site:Strict o Same-Site-Lax, como se explica en este artículo.

Algunos consejos para evitar los Client-Side Attacks

Ahora que ya hemos hablado de algunos de los tipos de vulnerabilidades y ataques más comunes, vamos a ver unos consejos importantes para tener en cuenta a la hora de realizar nuestro desarrollo. 
  • Desarrollo Seguro: En primer lugar, desarrollar de forma segura siempre debe formar parte del proceso de desarrollo ya que solventar un problema de seguridad cuando una aplicación está desplegada, es mucho más costoso y dañino para el usuario final, que analizar el código y realizar los cambios a priori. Para ello, es mejor trabajar con patrones de diseños conocidos y estudiados que resuelven problemas concretos, en lugar de reinventar la rueda constantemente, y usar soluciones lo más estandarizadas posibles.
  • Despliegue Seguro:No solo hay que hacer que la seguridad esté dentro del ciclo de vida de creación del software, así como en el despliegue de las nuevas releases, así que no solo la seguridad debe estar en el código, sino en los procesos de DevOps, pasando a ser SecDevOps.
Figura 11: Docker "SecDevOps"

  • Fortificación: Las reglas de la fortiticación son Mínimo Privilegio Posible, Mínima Superficie de Exposición y Defensa en Profundidad. Si aplicamos la segunda regla al desarrollo de fontends de aplicaciones web, compartimentar una aplicación, puede ser una buena forma de mitigar el impacto de una vulnerabilidad por lo que se de be optar por patrones como los MicroFrontEnds como una alternativa.
Contenido de Terceros Controlado: En caso de utilizar librerías de terceros, hemos de ser selectivos a la hora de elegir cual implementar ya que esto puede prevenir una o varias brechas de seguridad en nuestra aplicación. Se aconseja buscar librerías respaldadas por la comunidad y en las que se realice un mantenimiento habitual. También, si utilizamos recursos almacenados en servidores CDN, es muy recomendable utilizar el Tag Integrity que nos asegura la no alteración y la integridad del recurso que estamos utilizando. 

Figura 12: Ejemplo de uso de la Tag Integrity

Librerías vulnerables: Auditar las dependencias de nuestros proyectos es una buena práctica. Con el comando npm audit se mostrará una lista de los paquetes vulnerables que existen en nuestro proyecto y podremos ver cual de estas dependencias requieren una actualización.

Content Security Policies: Por último y no menos importante, recomendaros encarecidamente el uso de Content Security Policy. Es el nombre de la HTTP Header que utilizan los servidores web para sacar el máximo de partido de las opciones de fortificación que tienen los navegadores para mejorar la seguridad de una aplicación o página web.
Figura 13: CSP en la web de Facebook 

También se puede implementar vía meta tag. Las CSP suelen ser difíciles de configurar para que se ajusten a todos los comportamientos de todas las webapps en todos los navegadores, pero desde luego son la mejor opción para desplegar de forma fortificada una aplicación web, aunque sea en modo Reporting como hizo Google.

Figura 14: Etiqueta CSP como meta HTTP

Conclusiones

Fortificar una WebApp implica fortificar el end-point, así que desde el servidor web debemos utilizar todas las opciones no solo para fortificar nuestro código y las aplicaciones o frameworks server-side que utilicemos para soportar nuestra arquitectura, sino que deberemos también preocuparnos de todas las opciones de fortificación de los navegadores. Estos son solo algunos ejemplos de algunos ataques que se pueden dar client-side, y el número de cosas que hay que mirar en una aplicación web para tener la fortificación mejor posible es muy alta. 


Como podéis ver, un XSS se le puede escapar hasta a la propia Apple en Apple.com. Por eso, se recomienda tener cualquier WebApp expuesta en Internet, bajo un servicio de Pentesting Persistente, como el que hacemos desde ElevenPaths con el servicio Faast, donde miramos constantemente no solo las vulnerabilidades, sino también las debilidades en la fortificación del servidor y el cliente. Recuerda, si tú no auditas tu web, otro lo hará por ti... gratis.

Autor: Luis E. Álvarezdesarrollador y miembro del equipo Ideas Locas CDCO de Telefónica.

Figura 16: Contactar con Luis Eduardo Álvarez en MyPublicInbox

More info

No comments: