WordPress Hosting

¿Es peligroso eso del unfiltered_html?

En WordPress cualquier administrador o editor puede meter HTML y JavaScript sin filtrar dentro de una entrada, y eso incluye un <script> que se ejecuta en el navegador de cada visitante. No es un fallo, es una capacidad que viene de serie, se llama unfiltered_html, y la buena noticia es que, si quieres, porque tiene sus cosas, se corta con una sola línea en el wp-config.php.

Vamos a verlo, porque tiene más miga de la que parece.

Para empezar ¿qué es eso del unfiltered_html y qué hace?

WordPress filtra el HTML que guardas en las entradas con una función llamada wp_kses, que viene a ser el segurata que decide qué tags pasan y cuáles no, y por eso un suscriptor o un colaborador no puede colarte un <script> ni un <iframe> raro. Hasta ahí bien.

El problema es quién se puede saltar esa medida de seguridad. En una instalación normal, de un solo sitio, los administradores y los editores tienen la capacidad unfiltered_html, que les deja escribir el HTML que les dé la gana, sin filtrar ninguno. Lo que teclean va directo a la base de datos tal cual, scripts incluidos.

Si tienes una red multisitio con WordPress la cosa cambia, porque ahí solo los superadministradores la tienen, ni siquiera los administradores de cada subsitio. Así que este truco va sobre todo para las webs de un solo sitio, que son la mayoría.

¿Que esto es teórico? Ni de lejos. Ya conté en su día una vulnerabilidad en Divi, Extra y Divi Builder por la que usuarios de perfil bajo, como un simple autor, podían usar HTML sin filtrar en el contenido cuando editaban con el maquetador, justo lo que se supone que solo pueden hacer los administradores, lo que sería un escalado de privilegios de manual.

Por qué es un problema de seguridad, y no de confianza

El riesgo no es que tu editor sea mala gente, es que alguien se haga con su cuenta. Una contraseña reutilizada que aparece en una filtración, un phishing bien montado o un plugin comprometido que escala permisos, y de repente alguien tiene entre manos una cuenta con unfiltered_html.

Con esa cuenta no necesita romper nada, le basta con editar una entrada, pegar un <script> que robe cookies de sesión o redirija a los visitantes, guardar y a correr. Es XSS almacenado, del que se queda en tu base de datos y se ejecuta en el navegador de cada persona que abre esa página, tú incluido cuando entras al escritorio.

Mira qué fácil es impedir el unfiltered_html

La parte buena de todo esto es que el problema, que lo puede ser, se arregla simplemente definiendo una constante en el wp-config.php. Ábrelo por FTP o desde el gestor de archivos de tu hosting y añade esta línea antes de la que dice /* That's all, stop editing! Happy publishing. */:

define( 'DISALLOW_UNFILTERED_HTML', true );

Y ya está. A partir de ahí WordPress le quita la capacidad a todo el mundo, administradores y superadministradores incluidos, y todo lo que se guarde pasa por el filtro wp_kses como si lo escribiera un colaborador cualquiera. Ya no puedes meter una etiqueta <script>.

Para comprobar que funciona entra como administrador, mete un bloque de HTML personalizado con un <script>alert(1)</script> dentro, guarda y recarga. Si la constante está bien puesta, el script habrá desaparecido solo.

¿Se rompe algo si quito el unfiltered_html?

Esto no es gratis del todo,porque al capar el HTML sin filtrar WordPress también va a vaciar cosas seguramente normales que metas a mano como código, como un <iframe> de un mapa pegado en un bloque de HTML personalizado, un incrustado manual, un script de seguimiento que colabas en una entrada concreta, o ciertos atributos que wp_kses no admite por defecto.

Y luego hay otro efecto colateral, y es que desaparece también la opción de CSS adicional del personalizador. WordPress usa la capacidad edit_css para ese cuadro donde escribes CSS, y esa capacidad está enganchada por dentro a unfiltered_html, así que al desactivar una te llevas la otra por delante.

Lo mismo pasa con el CSS personalizado del editor de sitio en los temas de bloques. Si metes tus estilos por ahí tenlo claro antes de activar la constante.

Entonces, ¿cuándo la activo?

  • Sí, sin pensarlo, si tienes varios redactores, editores o autores, o si mantienes webs de clientes donde no controlas quién toca qué. El riesgo de una cuenta comprometida pesa mucho más que la comodidad de pegar un iframe de vez en cuando.
  • Con cuidado, o mejor no, si eres el único que edita, metes HTML crudo por el editor a menudo o dependes del CSS adicional del personalizador. En ese caso tienes salidas más finas.

Sí, hay otras maneras de protegerte sin hacerlo a la brava, para este segundo caso. Una es que en vez de capárselo a todos con la constante, quites la capacidad solo a los perfiles que no la necesitan, como editores y autores, con un filtro sobre map_meta_cap, y dejársela a los administradores. Solo tendrías que añadir un código como este:

/* Filtrar el HTML sin filtrar solo a los que no son administradores */
add_filter( 'map_meta_cap', 'ayudawp_limitar_unfiltered_html', 10, 3 );
 
function ayudawp_limitar_unfiltered_html( $caps, $cap, $user_id ) {
 
	// Solo actuamos sobre la capacidad de HTML sin filtrar
	if ( 'unfiltered_html' === $cap ) {
 
		// Leemos los datos del usuario directamente para no provocar
		// una llamada recursiva a este mismo filtro, como pasaría con user_can()
		$user = get_userdata( $user_id );
 
		// Si no es administrador (no tiene manage_options), se la denegamos
		if ( ! $user || empty( $user->allcaps['manage_options'] ) ) {
			$caps = array( 'do_not_allow' );
		}
	}
 
	return $caps;
}

Con esto los administradores siguen metiendo el HTML que quieran y a los editores se les filtra igual que a un colaborador, sin tocar el wp-config.php ni llevarte por delante el CSS adicional del personalizador. Y si lo que buscas es que tus redactores no puedan ni acercarse al HTML a mano, tienes el otro camino, desactivar el editor de código del editor de bloques. Depende de cómo trabajéis.

No te relajes que eso no es todo, aun te pueden colar código

La constante cierra la puerta del editor, que es la más grande, pero no es la única. Un plugin con una vulnerabilidad de XSS, un comentario mal filtrado o un formulario pueden colar un script por otro lado, y ahí esta línea no llega.

Para eso está la cabecera Content-Security-Policy (CSP), que es la que de verdad frena que un script se ejecute aunque haya conseguido meterse en tu base de datos.

Si tu política solo permite ejecutar JavaScript de tu propio dominio, el <script> del atacante que apunta fuera se queda mirando. Es la defensa con más rentabilidad contra el XSS, como ya expliqué en la guía de protección contra XSS.

Cabeceras CSP las gestionan muchos plugins de seguridad, pero el más completo en este sentido es Vigilante, que incluye incluso un comprobador de cabeceras. La idea es tener las dos capas trabajando juntas, la constante para que el script no entre por el editor y la CSP para que no se ejecute si entra por otro sitio.

¿En qué quedamos, impido el unfiltered_html o no?

Si en tu web publica más gente que tú, o llevas webs de clientes, la respuesta corta es sí. añade la línea al wp-config.php y te quitas de encima uno de los vectores de XSS más tontos y más habituales que hay. Pero administras y alimentas la web solo tú y usas el CSS adicional del personalizador o pegas iframes a mano, valora antes la alternativa de capárselo solo a ciertos perfiles.

Tienes más contexto en la lista completa de constantes de WordPress por si quieres seguir apretando tuercas en el wp-config.php, y en la guía de XSS para montar la parte de la CSP como es debido.

¿Tú la tenías capada o acabas de descubrir que tus editores podían hacer esto? Me lo cuentas ahí abajo, en los comentarios … o no.

Compártelo en tus redes
Resúmelo con tu IA

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en las estrellas para valorarlo!

Promedio de puntuación 5 / 5. Total de votos: 3

¡Todavía no hay votos! Sé el primero en valorar este contenido.

Ya que has encontrado útil este contenido...

¡Sígueme en las redes sociales!

¿Te gustó este artículo? ¡Ni te imaginas lo que te estás perdiendo en YouTube!



Sobre el autor

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio