html-sanitize: módulo de NGINX para sanitizar HTML 5 con elementos, atributos y CSS en lista blanca
Instalación
Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:
- RedHat Enterprise Linux 7, 8, 9 y 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 y Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-html-sanitize
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-html-sanitize
Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:
load_module modules/ngx_http_html_sanitize_module.so;
Este documento describe nginx-module-html-sanitize v0.2.6 lanzado el 07 de marzo de 2026.
Ejemplo
Hay un ejemplo de configuración de nginx de acuerdo con https://dev.w3.org/html5/html-author/#the-elements como el siguiente:
server {
listen 8888;
location = /sanitize {
# Establecer explícitamente la codificación utf-8
add_header Content-Type "text/html; charset=UTF-8";
client_body_buffer_size 10M;
client_max_body_size 10M;
html_sanitize on;
# Ver https://dev.w3.org/html5/html-author/#the-elements
# Elemento raíz
html_sanitize_element html;
# Metadatos del documento
html_sanitize_element head title base link meta style;
# Scripting
html_sanitize_element script noscript;
# Secciones
html_sanitize_element body section nav article aside h1 h2 h3 h4 h5 h6 header footer address;
# Agrupación de contenido
html_sanitize_element p hr br pre dialog blockquote ol ul li dl dt dd;
# Semántica de nivel de texto
html_sanitize_element a q cite em strong small mark dfn abbr time progress meter code var samp kbd sub sup span i b bdo ruby rt rp;
# Ediciones
html_sanitize_element ins del;
# Contenido embebido
htlm_sanitize_element figure img iframe embed object param video audio source canvas map area;
# Datos tabulares
html_sanitize_element table caption colgroup col tbody thead tfoot tr td th;
# Formularios
html_sanitize_element form fieldset label input button select datalist optgroup option textare output;
# Elementos interactivos
html_sanitize_element details command bb menu;
# Elementos misceláneos
html_sanitize_element legend div;
html_sanitize_attribute *.style;
html_sanitize_attribute a.href a.hreflang a.name a.rel;
html_sanitize_attribute col.span col.width colgroup.span colgroup.width;
html_sanitize_attribute data.value del.cite del.datetime;
html_sanitize_attribute img.align img.alt img.border img.height img.src img.width;
html_sanitize_attribute ins.cite ins.datetime li.value ol.reversed ol.stasrt ol.type ul.type;
html_sanitize_attribute table.align table.bgcolor table.border table.cellpadding table.cellspacing table.frame table.rules table.sortable table.summary table.width;
html_sanitize_attribute td.abbr td.align td.axis td.colspan td.headers td.rowspan td.valign td.width;
html_sanitize_attribute th.abbr th.align th.axis th.colspan th.rowspan th.scope th.sorted th.valign th.width;
html_sanitize_style_property color font-size;
html_sanitize_url_protocol http https tel;
html_sanitize_url_domain *.google.com google.com;
html_sanitize_iframe_url_protocol http https;
html_sanitize_iframe_url_domain facebook.com *.facebook.com;
}
}
Y se recomienda usar el siguiente comando para sanitizar HTML5:
$ curl -X POST -d "<h1>Hello World </h1>" http://127.0.0.1:8888/sanitize?element=2&attribute=1&style_property=1&style_property_value=1&url_protocol=1&url_domain=0&iframe_url_protocol=1&iframe_url_domain=0
<h1>Hello World </h1>
Esta cadena de consulta element=2&attribute=1&style_property=1&style_property_value=1&url_protocol=1&url_domain=0&iframe_url_protocol=1&iframe_url_domain=0 es la siguiente:
- element=2: salida de elementos en lista blanca por html_sanitize_element
- attribute=1: salida de cualquier atributo por html_sanitize_attribute
- style_property=1: salida de cualquier propiedad de estilo por html_sanitize_style_property
- style_property_value=1: comprobar el valor del estilo para la función url y la función expression para evitar inyecciones XSS por style_property_value
- url_protocol=1: comprobar el protocolo de URL en lista blanca para URL absolutas por html_sanitize_url_protocol
- url_domain=0: no comprobar el dominio de la URL para URL absolutas
- iframe_url_protocol=1: es lo mismo que url_protocol pero solo para
iframe.srcpor html_sanitize_iframe_url_protocol - iframe_url_domain=0: es lo mismo que url_domain pero solo para
iframe.srcpor html_sanitize_iframe_url_domain
Con ngx_http_html_sanitize_module, tenemos la capacidad de especificar si se deben mostrar los elementos de HTML5, atributos y propiedades de CSS en línea mediante directive y querystring como sigue:
elemento en lista blanca
- deshabilitar elemento:
si no queremos mostrar ningún elemento, podemos hacerlo de la siguiente manera:
curl -X POST -d "<h1>h1</h1>" http://127.0.0.1:8888/sanitize?element=0
- habilitar elemento:
si queremos mostrar cualquier elemento, podemos hacerlo de la siguiente manera:
$ curl -X POST -d "<h1>h1</h1><h7>h7</h7>" http://127.0.0.1:8888/sanitize?element=1
<h1>h1</h1><h7>h7</h7>
- habilitar elemento en lista blanca:
si queremos mostrar elementos en lista blanca, podemos hacerlo de la siguiente manera
$ curl -X POST -d "<h1>h1</h1><h7>h7</h7>" http://127.0.0.1:8888/sanitize?element=1
<h1>h1</h1>
atributo en lista blanca
- deshabilitar atributo:
si no queremos mostrar ningún atributo, podemos hacerlo de la siguiente manera:
curl -X POST -d "<h1 ha=\"ha\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=0"
<h1>h1</h1>
- habilitar atributo:
si queremos mostrar cualquier atributo, podemos hacerlo de la siguiente manera:
$ curl -X POST -d "<h1 ha=\"ha\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1"
<h1 ha="ha">h1</h1>
- habilitar atributo en lista blanca:
si queremos mostrar atributos en lista blanca, podemos hacerlo de la siguiente manera:
$ curl -X POST -d "<img src=\"/\" ha=\"ha\" />" "http://127.0.0.1:8888/sanitize?element=1&attribute=2"
<img src="/" />
propiedad de estilo en lista blanca
- deshabilitar propiedad de estilo:
si no queremos mostrar ninguna propiedad de estilo, podemos hacerlo de la siguiente manera:
# No se mostrará ninguna propiedad de estilo
curl -X POST -d "<h1 style=\"color:red;\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=0"
<h1>h1</h1>
- habilitar propiedad de estilo:
si queremos mostrar cualquier propiedad de estilo, podemos hacerlo de la siguiente manera:
$ curl -X POST -d "<h1 style=\"color:red;text-align:center;\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=1"
<h1 style="color:red;text-align:center">h1</h1>
- habilitar propiedad de estilo en lista blanca:
si queremos mostrar propiedades de estilo en lista blanca, podemos hacerlo de la siguiente manera:
$ curl -X POST -d "<h1 style=\"color:red;text-align:center;\" >h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=2"
<h1 style="color:red;">h1</h1>
Descripción
Ahora la implementación de ngx_http_html_sanitize_module se basa en gumbo-parser y katana-parser. Y hacemos la combinación sobre ello y lo ejecutamos en nginx como un servicio web central mantenido por profesionales de seguridad para descartar diferencias a nivel de lenguaje. Si queremos obtener un rendimiento más alto (aquí está el brenchmark), se recomienda escribir una biblioteca a nivel de lenguaje que envuelva la biblioteca pura en C para superar la sobrecarga de la transmisión de red.
Benchmark
Pruebas con wrk -s benchmarks/shot.lua -d 60s "http://127.0.0.1:8888" en Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz y 64GB de memoria
| Nombre | Tamaño | Latencia Promedio | QPS |
|---|---|---|---|
| hacker_news.html | 30KB | 9.06ms | 2921.82 |
| baidu.html | 76KB | 13.41ms | 1815.75 |
| arabic_newspapers.html | 78KB | 16.58ms | 1112.70 |
| bbc.html | 115KB | 17.96ms | 993.12 |
| xinhua.html | 323KB | 33.37ms | 275.39 |
| google.html | 336KB | 26.78ms | 351.54 |
| yahoo.html | 430KB | 29.16ms | 323.04 |
| wikipedia.html | 511KB | 57.62ms | 160.10 |
| html5_spec.html | 7.7MB | 1.63s | 2.00 |
Directiva
html_sanitize
sintaxis: html_sanitize on | off
predeterminado: html_sanitize on
contexto: location
Especifica si habilitar el controlador de sanitización HTML en el contexto de la ubicación.
html_sanitize_hash_max_size
sintaxis: html_sanitize_hash_max_size size
predeterminado: html_sanitize_hash_max_size 2048
contexto: location
Establece el tamaño máximo de las tablas hash de elementos, atributos, propiedades de estilo, protocolos de URL, dominios de URL, protocolos de URL de iframe y dominios de URL de iframe.
html_sanitize_hash_bucket_size
sintaxis: html_sanitize_hash_bucket_size size
predeterminado: html_sanitize_hash_bucket_size 32|64|128
contexto: location
Establece el tamaño del bucket para elementos, atributos, propiedades de estilo, protocolos de URL, dominios de URL, protocolos de URL de iframe y dominios de URL de iframe. El valor predeterminado depende del tamaño de la línea de caché del procesador.
html_sanitize_element
sintaxis: html_sanitize_element element ...
predeterminado: -
contexto: location
Establece los elementos HTML5 en lista blanca cuando se habilita el elemento en lista blanca configurando el modo de lista blanca de la cadena de consulta element como sigue:
html_sanitize_element html head body;
html_sanitize_attribute
sintaxis: html_sanitize_attribute attribute ...
predeterminado: -
contexto: location
Establece los atributos HTML5 en lista blanca cuando se habilita el elemento en lista blanca configurando el modo de lista blanca de la cadena de consulta attribute como sigue:
html_sanitize_attribute a.href h1.class;
PS: el formato del atributo debe ser el mismo que element.attribute y soporta *.attribute (asterisco de prefijo) y element.* (asterisco de sufijo)
html_sanitize_style_property
sintaxis: html_sanitize_style_property property ...
predeterminado: -
contexto: location
Establece la propiedad CSS en lista blanca cuando se habilita el elemento en lista blanca configurando el modo de lista blanca de la cadena de consulta style_property como sigue:
html_sanitize_style_property color background-color;
html_sanitize_url_protocol
sintaxis: html_sanitize_url_protocol [protocol] ...
predeterminado: -
contexto: location
Establece el protocolo de URL permitido en linkable attribute cuando solo la URL es absoluta en lugar de relativa y habilita la verificación del protocolo de URL configurando el modo de verificación de la cadena de consulta url_protocol como sigue:
html_sanitize_url_protocol http https tel;
html_sanitize_url_domain
sintaxis: html_sanitize_url_domain domain ...
predeterminado: -
contexto: location
Establece el dominio de URL permitido en linkable attribute cuando solo la URL es absoluta en lugar de relativa y habilita la verificación del protocolo de URL, la verificación del dominio de URL configurando el modo de verificación de la cadena de consulta url_protocol y el modo de verificación de la cadena de consulta url_domain[#url_domain] como sigue:
html_sanitize_url_domain *.google.com google.com;
html_sanitize_iframe_url_protocol
sintaxis: html_sanitize_iframe_url_protocol [protocol] ...
predeterminado: -
contexto: location
es lo mismo que html_sanitize_url_protocol pero solo para el atributo iframe.src
html_sanitize_iframe_url_protocol http https tel;
html_sanitize_iframe_url_domain
sintaxis: html_sanitize_iframe_url_domain [protocol] ...
predeterminado: -
contexto: location
es lo mismo que html_sanitize_url_domain pero solo para el atributo iframe.src
html_sanitize_iframe_url_domain *.facebook.com facebook.com;
linkable_attribute
El atributo enlazable es el siguiente:
- a.href
- blockquote.cite
- q.cite
- del.cite
- img.src
- ins.cite
- iframe.src
- función URL de CSS
Querystring
la cadena de consulta de la URL de solicitud se utiliza para controlar la acción interna de ngx_http_html_sanitize_module.
document
valor: 0 o 1
predeterminado: 0
contexto: querystring
Especifica si se debe agregar <!DOCTYPE> al cuerpo de la respuesta.
html
valor: 0 o 1
predeterminado: 0
contexto: querystring
Especifica si se debe agregar <html></html> al cuerpo de la respuesta.
script
valor: 0 o 1
predeterminado: 0
contexto: querystring
Especifica si se permite <script></script>.
style
valor: 0 o 1
predeterminado: 0
contexto: querystring
Especifica si se permite <style></style>.
context
valor: [0, 150)
predeterminado: 38(GUMBO_TAG_DIV)
contexto: querystring
Especifica el contexto del gumbo-parser con el valor en este archivo tag_enum.h.
element
valor: 0、1、2
predeterminado: 0
contexto: querystring
Especifica el modo de salida del elemento con el valor como sigue:
- 0: no mostrar elemento
- 1: mostrar todos los elementos
- 2: mostrar elementos en lista blanca
attribute
valor: 0、1、2
predeterminado: 0
contexto: querystring
Especifica el modo de salida del atributo con el valor como sigue:
- 0: no mostrar atributos
- 1: mostrar todos los atributos
- 2: mostrar atributos en lista blanca
style_property
valor: 0、1、2
predeterminado: 0
contexto: querystring
Especifica el modo de salida de la propiedad CSS con el valor como sigue:
- 0: no mostrar propiedad CSS
- 1: mostrar todas las propiedades CSS
- 2: mostrar propiedades CSS en lista blanca
style_property_value
valor: 0、1
predeterminado: 0
contexto: querystring
Especifica el modo de salida del valor de la propiedad CSS con el valor como sigue:
- 0: no comprobar el valor de la propiedad CSS
- 1: comprobar el valor de la propiedad CSS para la función URL y la función de expresión de IE para evitar inyecciones XSS.
url_protocol
valor: 0、1
predeterminado: 0
contexto: querystring
Especifica si se debe comprobar el protocolo de URL en linkable_attribute. El valor es el siguiente:
- 0: no comprobar el protocolo de URL
- 1: mostrar protocolo de URL en lista blanca
url_domain
valor: 0、1
predeterminado: 0
contexto: querystring
Especifica si se debe comprobar el dominio de URL en linkable_attribute cuando se habilita la verificación de url_protocol. El valor es el siguiente:
- 0: no comprobar el dominio de URL
- 1: mostrar dominio de URL en lista blanca
iframe_url_protocol
valor: 0、1
predeterminado: 0
contexto: querystring
es lo mismo que url_protocol pero solo para iframe.src.
iframe_url_domain
valor: 0、1
predeterminado: 0
contexto: querystring
es lo mismo que url_domain pero solo para iframe.src.
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-html-sanitize.