Aprende a prevenir ataques XSS y eliminar nodos html no permitidos en markdown usando una biblioteca de analizador de markdown en PHP como Parsedown.

Cómo prevenir ataques XSS y no permitir etiquetas específicas en HTML generadas por un analizador PHP Markdown

Markdown utiliza una sintaxis de formato muy fácil de usar para lograr lo mismo que hace el HTML o el formato de texto enriquecido y su proceso de análisis en el lado del servidor también es bastante fácil con las herramientas adecuadas. Sin embargo, si no maneja correctamente el HTML generado por su analizador de Markdown favorito, tendrá problemas si alguien descubre que su aplicación es vulnerable a un ataque XSS. Un ataque XSS se refiere a un ataque de inyección de código en el que un atacante puede ejecutar scripts maliciosos en un sitio web o aplicación web. El punto es que una vulnerabilidad XSS solo puede explotarse si la carga útil (el script malicioso) que inserta el atacante se analiza como HTML en el navegador de la víctima.

Seguramente has oído hablar de las funciones de PHP htmlentitieshtmlspecialcharsetc., funciones que te permiten codificar y decodificar símbolos usados ​​en HTML, pero es demasiado problemático trabajar con él solo si no tienes mucho tiempo. Principalmente, su analizador debe proporcionar una funcionalidad correcta, sin embargo, también deben ser flexibles y útiles, pero a veces, debido a las características de su proyecto, es posible que no funcione 100% correctamente. Por ejemplo, la siguiente rebaja:

# Hello World

Soy programador y quiero escribir código. No escribo código con malas intenciones, solo comparto mis conocimientos

```html
<script>
    alert("First alert");
</script>
```

<script>alert("second alert");</script>

<img src="http://url.to.file.which/not.exist" onerror=alert(document.cookie);>

Analizado en HTML usando el analizador de rebajas de cebeb y renderizado en el navegador, solo alertará "segunda alerta" . Esto se debe a que el analizador es lo suficientemente inteligente como para convertir todo el contenido dentro de un bloque de código en sus respectivas entidades HTML automáticamente. Sin embargo, la etiqueta de secuencia de comandos fuera de cualquier bloque de código aún está siendo interpretada por el navegador como JavaScript, lo que obviamente es un problema y la imagen cargada desde un archivo no existente también se activará.

En este artículo le mostraremos cómo evitar la inserción desde JavaScript.

Solución con Parsedown

Parsedown hace las cosas realmente fáciles para usted al escapar de todo el marcado dentro del markdown que proporciona para analizar. Sin embargo, no está habilitado de forma predeterminada y no es suficiente para prevenir todas las formas de ataques XSS. Por esta razón, le recomendamos que, en caso de que desee utilizar una versión segura de Parsedown, utilice el paquete secureparsedown. Los cambios realizados por Aidan Woods  a la biblioteca de análisis original proporcionan una implementación de un modo seguro que protegerá el HTML de ser vulnerable a XSS.

En este caso, no se ha publicado la versión 1.7.0 con los cambios de Aidan, por lo que hasta la fecha puedes descargar la versión segura de parsedown desde el siguiente paquete:

composer require aidantwoods/secureparsedown

La ventaja de usar esta versión es que usará la última versión de Parsedown pero también crea el modo seguro. O si lo prefiere, modifique manualmente su composer.jsonarchivo y luego ejecute composer install:

{
    "require": {
        "aidantwoods/secureparsedown": "^1.0"
    }
}

Una vez instalado, use Parsedown como lo hace habitualmente y no olvide usar los métodos setMarkupEscaped y setSafeModepara proporcionar un HTML seguro para representar:

<?php

use Aidantwoods\SecureParsedown\SecureParsedown;

$markdown = "# Title <script>alert('XSS Attack ...');</script>";

$Parsedown = new SecureParsedown;

// Escapa de la reducción de entrada para evitar que se produzca cualquier html y habilita el análisis en modo seguro
$Parsedown->setSafeMode(true);

// HTML seguro
echo $Parsedown->text($markdown);

Esto es útil porque todo el texto dentro de Markdown interpretado como HTML se convertirá a su representación de entidad html inofensiva (que evita los ataques XSS). Sin embargo, esta función solo está disponible con esta biblioteca. Si desea evitar que aparezcan algunas etiquetas específicas, implemente la solución también desde otras bibliotecas de analizadores.

Solución con otras bibliotecas de analizadores

Si está utilizando otro analizador Markdown en PHP, probablemente no tendrá la misma característica de Parsedown. En este caso, deberá instalar la biblioteca htmlpurifier. HTML Purifier es una biblioteca de filtros HTML que cumple con los estándares y está escrita en PHP. HTML Purifier no solo eliminará todo el código malicioso (más conocido como XSS) con una lista blanca completamente auditada, segura pero permisiva, sino que también se asegurará de que sus documentos cumplan con los estándares, algo que solo se puede lograr con un conocimiento integral de las especificaciones del W3C.

Para instalar htmlpurifier en su proyecto con Composer, ejecute el siguiente comando en su terminal:

composer require "ezyang/htmlpurifier":"dev-master"

Una vez que la biblioteca se haya instalado en su proyecto usando Composer, podrá usarla fácilmente. La forma más fácil de lograr su objetivo de eliminar las etiquetas de script del HTML generado a partir de la rebaja procesada por su analizador es prohibiendo etiquetas específicas con la opción HTML.ForbiddenElements (donde cada etiqueta es un elemento de la matriz de argumentos):

<?php 

// La fuente de tu markdown
$markdown = "# Title <script>alert('Super unsafe markdown ...');</script>";

// Cree una instancia de su analizador si está disponible ...
$parser = new YourFavoriteMarkdownParserExample();

// Este contiene el HTML generado a partir de su markdown
$parsedMarkdown = $parser->parse($markdown);

// Inicializar un objeto de configuración del purificador html
$config = HTMLPurifier_Config::createDefault();

// Los nodos HTML que desea evitar que se procesen
// como segundo argumento dentro de una matriz
$config->set('HTML.ForbiddenElements', array('script','applet'));

// Inicializar purificador html
$purifier = new HTMLPurifier($config);

// Purifica el HTML generado y
// ¡Utilice este HTML seguro para mostrarlo en el navegador!
$HTMLWithoutForbiddenTags = $purifier->purify($parsedMarkdown);

Alternativamente, si desea un control total de las etiquetas que se procesarán, puede decidir qué etiquetas HTML se pueden procesar y qué atributos:

<?php 

// La fuente de tu markddown
$markdown = "# Title <script>alert('Super unsafe markdown ...');</script>";

$parser = new YourFavoriteMarkdownParserExample();
        
$config = \HTMLPurifier_Config::createDefault();

// Permitir texto sin etiqueta, por ejemplo, P o DIV (texto sin formato, obviamente necesario para la rebaja)
$config->set('Core.LexerImpl', 'DirectLex');

// Definir manualmente qué elementos se pueden renderizar
// En este ejemplo, permitimos (casi) todos los elementos básicos que se convierten con markdown
$config->set('HTML.Allowed', 'h1,h2,h3,h4,h5,h6,br,b,i,strong,em,a,pre,code,img,tt,div,ins,del,sup,sub,p,ol,ul,table,thead,tbody,tfoot,blockquote,dl,dt,dd,kbd,q,samp,var,hr,li,tr,td,th,s,strike');
// The attributes are up to you
$config->set('HTML.AllowedAttributes', 'img.src,*.style,*.class, code.class,a.href,*.target');

// Cree una instancia del purificador con la configuración
$purifier = new \HTMLPurifier($config);

// Imprime el HTML purificado
echo $purifier->purify($parser->text($markdown));

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores