Usar Playwright para probar ataques XSS de forma automatizada

En el vídeo de esta semana, de mi serie sobre DevSecOps, te contaba diferentes test que te puedes hacer desde el punto de vista de seguridad, para que puedas comprobar si tu código ya está listo para pasar a la fase de release, dentro de una cultura DevSecOps 😊

Hoy quiero compartir contigo una de las demos que mostré en el mismo, donde uso Playwright para probar si una web es vulnerable a ataques del tipo Cross Site Scripting (XSS).

¿Qué es Playwright?

Se trata de un framework creado por Microsoft que te permite definir test funcionales de forma automatizada. Además, recientemente se ha aunciado, en Public Preview, un nuevo servicio en Azure llamado Microsoft Playwright Service, que te permitirá lanzar estos test desde la nube de Microsoft.

Crear un proyecto para Playwright

Antes de crear tus test, lo primero que necesitas en crear un proyecto con todo lo que necesita Playwright para funcionar. Para ello, solo tienes que lanzar el siguiente comando:

npm init playwright@latest

Este lanzará un asistente donde podrás elegir entre TypeScript y JavaScript, en qué directorio quieres almacenar los tests, si usas GitHub Actions también te genera un flujo para lanzar lo que generes como parte de tu integración continua y, por último, te facilita la instalación de todos los navegadores que necesitará para poder hacer las pruebas en todos ellos.

Asistente de Playwright

Una vez finalice ya podrás generar tus primeros tests.

Test para probar el ataque Cross Site Scripting

Para poder probar este ataque voy a hacer uso de la página www.domxss.com, la cual es una página intencionadamente vulnerable 😊 El test que he generado es el siguiente:

import { test, expect } from '@playwright/test';
test('injects script in name variable', async ({ page }) => {
    // Hack message
    const hack_message = 'owned';
    const xss = `<script>alert('${hack_message}')</script>`;
    var alert = '';
    //https://playwright.dev/docs/dialogs
    page.on('dialog', async dialog => {
        console.log(dialog.message());
        alert = dialog.message();       
        dialog.accept();
    });
    // Go to http://www.domxss.com/domxss/01_Basics/00_simple_noHead.html?name= with xss in name variable
    await page.goto(`http://www.domxss.com/domxss/01_Basics/00_simple_noHead.html?name=${xss}`);
    // Wait for page to load
    await page.waitForLoadState('networkidle');
    // Expect alert to be xss
    await expect(alert).not.toBe(hack_message);
});

Como ves, el mismo es bastante simple: en él defino cuál es el mensaje que voy a incluir como parte del alert que voy a intentar inyectar en la página y me reservo una variable llamada alert 🤓 donde, en teória, si consigo que la inyección de este código sea satisfactoria, incluirá el mensaje que he añadido en la constante hack_message. Por otro lado Playwright auto-acepta los dialogos que aparezcan durante el test, pero es posible manejar este comportamiento tal y como se comenta aquí. Por lo que me suscribo al evento dialog por si consigo inyectar el código poder guardar el valor del mensaje en esta variable alert. Con esta configuración hecha, me dirijo a la página vulnerable e intento inyectar el script en la variable name. Si ha ido mal 🤓 el test fallará y confirmará que la página igual es un poquito vulnerable a este tipo de ataques.

El código de mi ejemplo lo tienes en este repositorio en mi cuenta de GitHub.

¡Saludos! 👋🏻