Proteger WordPress (y cualquier otro sitio) con el firewall de Cloudflare

WordPress es una plataforma muy potente para la creación de sitios y aplicaciones web de todo tipo. Grandes marcas como BBC, MTV, Sony, Disney e incluso Facebook la usan para publicitar sus productos y servicios. La ventaja de WordPress es que con muy poco esfuerzo puedes montar un sitio web completamente funcional, y con los plugins disponibles a un par de clics la personalización y características con las que puedes interactuar es virtualmente infinita.

Pero esto tiene un load oscuro: su popularidad también atrae a personas malintencionadas que, con fines particulares, toman el control de la plataforma sin autorización. En el año 2019 se descubrieron 11 vulnerabilidades propias de la plataforma, y a esto se suman la cantidad de plugins que tienen puertas traseras, ya sea porque es intencionado o por una programación con carencias en tema de seguridad.

Por eso, es muy importante que al usar una herramienta como WordPress, se piense en seguridad, al menos una básica. Y esto aplica para cualquier tipo de plataforma o lenguaje que sirva contenido dinámico. Muchos pensarán que WordPress, al ser programado en PHP, contiene esta cantidad de vulnerabilidades, pero por ejemplo Django, escrito en Python y con una tendencia de uso cada vez mayor, se le reportaron 8 vulnerabilidades en 2019, a solo 3 de alcanzar a nuestro protagonista.

Así que la protección y seguridad debe aplicarse a todo, y con la ayuda del firewall de Cloudflare podemos proteger la gran mayoría de nuestra aplicación web, sin importar la plataforma que usemos.

Configurar el firewall de Cloudflare

Lo primero que necesitamos es que nuestro sitio esté correctamente configurado y use los DNS de Cloudflare. Si no tienes una cuenta puedes crear una. Estos pasos se pueden aplicar con una suscripción gratuita.

Recuerda configurar la zona DNS del dominio para que pase a través del proxy reverso de Cloudflare.

Ejemplo de zona DNS con proxy reverso habilitado para los registros A y CNAME www.

Esto garantizará que al ingresar por el nombre de dominio, todo el tráfico pase por el firewall. Recuerda que dentro del servidor también tienes que forzar que todo el tráfico pase por el nombre de dominio y no, por ejemplo, por acceso directo a través de la dirección IP.

Ahora bien, la parte más importante de esta configuración se enfoca en el módulo de Firewall. Un firewall puede permitir o bloquear el tráfico basándose en reglas predefinidas y personalizadas. Las reglas son expresiones que, al coincidir con algún dato del visitante, ejecuta cierta acción. Por ejemplo, yo puedo escribir una regla en donde la condición es que el visitante debe estar en latinoamérica, y la acción sea mostrar un desafío antispam. Pues ahora todos los visitantes que provengan de latinamérica se les motrará un captcha, y los visitantes de otras partes del mundo entrarán directamente. Pero la idea no es bloquear a los visitantes por su zona geográfica, no al menos en este caso.

La suscripción gratuita de Cloudflare permite establecer hasta 5 reglas de firewall. Para la configuración que haremos aquí es suficiente. El orden de las reglas es importante, ya que se aplicarán de la primera hacia la última, en la primera coincidencia.

El objetivo de esta configuración es bloquear los bots basados en su número de sistema autónomo. Este número identifica una dirección IP contra la red o datacenter que usa. Por ejemplo, en vez de coleccionar todos los rangos de direcciones IP que usa Amazon Web Services, que tomaría años, mucho tráfico y gran poder de análisis, simplemente averiguamos el número de la red y toda dirección IP que provenga de dicha red, es de Amazon.

Ahora, Amazon permite a cualquier persona crear servidores en la nube y montar cualquier cosa, por ejemplo, un script que identifique y explote las vulnerabilidades de un sitio web.

El objetivo es que dichos scripts, montados en Amazon, sean bloqueados. Pero no todo el tráfico de Amazon es malo: no quisiéramos bloquear el tráfico de, por ejemplo, el CDN Cloudfront, que también reside en la red de Amazon.

Pero tranquilo: esta configuración de firewall se encargará de todo esto.

Primera regla: whitelist

Debemos garantizar que ninguna regla bloquee el acceso de ciertos bots sanos como lo son el bot de Google, que indexa las páginas web, o los bots de Jetpack que mantienen permanente contacto con nuestro sitio. Entonces, en la opción Reglas de firewall, hacemos clic en el botón Crear una regla de firewall. La configuramos del siguiente modo:

  • Nombre: Whitelist (o como quieran llamarle)
  • Acción: Permitir

Y luego buscamos el enlace Editar expresión, y pegamos el siguiente contenido:

(ip.geoip.asnum in {16509 14618} and http.request.method eq "GET") or (cf.client.bot)
La primera regla debe quedar con un aspecto similar al de esta imagen.

Esta regla garantizará que el CDN de Cloudfront y todos los bots conocidos (y sanos) nunca sean bloqueados por las demás reglas.

Ahora buscamos el botón Guardar, damos clic, y estamos listos para las demás reglas.

Segunda regla: BLOCK

El objetivo de esta regla es bloquear radicalmente cualquier solicitud en donde nosotros tengamos la completa certeza de que son fraudulentas. Por ejemplo: he recibido múltiples ataques desde direcciones IP que pertenecen al sistema autónomo GlobalCom Telecommunications PLC, con ASN 196725, de Palestina. Como mi público objetivo no es de Palestina, y recibo este tipo de ataques, tengo la certeza de que todas las solicitudes desde ese territorio serán fraudulentas, por lo que uso esta regla BLOCK para que nunca pasen. Si hay algún bot sano de Palestina, pues ese podrá pasar de acuerdo a la primera regla, pero todo lo demás será bloqueado.

  • Nombre: Block
  • Acción: Bloquear
La segunda regla debe quedar similar a la de esta imagen.

Tercera (y cuarta) regla: bloqueo por desafío

El objetivo de esta regla es mostrar un desafío (anti-bot) a los visitantes que sospechemos que son amenazas. Como no tenemos la certeza completa de que son amenazas, o que es probable que un visitante legítimo use esas redes (una VPN desplegada sobre estas redes o situaciones similares), no podemos usar la segunda regla de block, ya que podríamos estar bloqueando el tráfico legítimo.

En esta regla también podemos colocar fragmentos de URL (como /wp-login.php) para evitar los ataques automatizados (descubrir usuarios y contraseñas por fuerza bruta).

A lo largo de los últimos dos años he recolectado números ASN desde donde han provenido la mayoría de los ataques que he recibido. Como no tengo la certeza de que el tráfico de todos estos números es ilegítimo, solo pondré el desafío.

En esta lista de ASN van incluidas algunas redes y datacenters conocidos como OVH, Azure, y muchas redes de China. Antes de implantar esta regla, recomiendo fuertemente revisar los ASN.

Ahora, las reglas de Cloudflare tienen un límite de expresión de ~4,000 bytes (o caracteres). O sea que, una vez llenen la caja de expresión con 4,000 caracteres, deben crear otra regla para colocar más ASN.

Esto me ha pasado a mí, y por eso tengo dos reglas de bloqueo por desafío.

  • Nombre: Challenge 1 y Challenge 2
  • Acción: Desafío (CAPTCHA)

La primera regla es

(ip.geoip.asnum eq 14618) or (ip.geoip.asnum eq 43317) or (ip.geoip.asnum eq 63949) or (ip.geoip.asnum eq 14061) or (ip.geoip.asnum eq 61053) or (ip.geoip.asnum eq 16276) or (ip.geoip.asnum eq 4760) or (ip.geoip.asnum eq 58262) or (ip.geoip.asnum eq 9123) or (ip.geoip.asnum eq 20473) or (ip.geoip.asnum eq 2200) or (ip.geoip.asnum eq 5033) or (ip.src in {52.224.0.0/11}) or (ip.src in {34.87.70.0/24}) or (ip.geoip.asnum eq 27823) or (ip.geoip.asnum eq 133469) or (ip.geoip.asnum eq 21487) or (ip.geoip.asnum eq 24938) or (ip.geoip.asnum eq 135161) or (ip.geoip.asnum eq 35017) or (ip.geoip.asnum eq 42055) or (ip.geoip.asnum eq 56694) or (ip.geoip.asnum eq 26496) or (ip.geoip.asnum eq 38901) or (ip.geoip.asnum eq 53667) or (ip.geoip.asnum eq 37611) or (ip.geoip.asnum eq 12876) or (ip.geoip.asnum eq 5483) or (ip.geoip.asnum eq 62239) or (ip.geoip.asnum eq 12322) or (ip.geoip.asnum eq 262914) or (ip.geoip.asnum eq 50004) or (ip.geoip.asnum eq 49544) or (ip.geoip.asnum eq 9009) or (ip.geoip.asnum eq 31034) or (ip.geoip.asnum eq 60781) or (ip.geoip.asnum eq 37963) or (ip.geoip.asnum eq 134548) or (ip.geoip.asnum eq 16509) or (ip.geoip.asnum eq 47331) or (ip.geoip.asnum eq 9299) or (ip.geoip.asnum eq 17974) or (ip.geoip.asnum eq 262663) or (ip.geoip.asnum eq 23969) or (ip.geoip.asnum eq 8452) or (ip.geoip.asnum eq 45820) or (ip.geoip.asnum eq 39001) or (ip.geoip.asnum eq 12849) or (ip.geoip.asnum eq 4134) or (ip.geoip.asnum eq 45916) or (ip.geoip.asnum eq 9416) or (ip.geoip.asnum eq 8402) or (ip.geoip.asnum eq 17639) or (ip.geoip.asnum eq 50673) or (ip.geoip.asnum eq 31898) or (ip.geoip.asnum eq 4837) or (ip.geoip.asnum eq 4766) or (ip.geoip.asnum eq 198605) or (ip.geoip.asnum eq 131414) or (ip.geoip.asnum eq 50810) or (ip.geoip.asnum eq 60976) or (ip.geoip.asnum eq 9658) or (ip.geoip.asnum eq 44049) or (ip.geoip.asnum eq 31863) or (ip.geoip.asnum eq 5588) or (ip.geoip.asnum eq 132372) or (ip.geoip.asnum eq 35913) or (ip.geoip.asnum eq 4812) or (ip.geoip.asnum eq 200557) or (ip.geoip.asnum eq 32181) or (ip.geoip.asnum eq 28753) or (ip.geoip.asnum eq 17877) or (ip.geoip.asnum eq 3786) or (ip.geoip.asnum eq 51559) or (ip.geoip.asnum eq 63734) or (ip.geoip.asnum eq 42926) or (ip.geoip.asnum eq 852) or (ip.geoip.country eq "CN") or (ip.geoip.asnum eq 45102) or (ip.geoip.asnum eq 4765) or (ip.geoip.asnum eq 55313) or (ip.geoip.asnum eq 48635) or (ip.geoip.asnum eq 131392) or (ip.geoip.asnum eq 51167) or (ip.geoip.asnum eq 8732) or (ip.geoip.asnum eq 197226) or (ip.geoip.asnum eq 34533) or (ip.geoip.asnum eq 48874) or (ip.geoip.asnum eq 55933) or (ip.geoip.asnum eq 26346) or (ip.geoip.asnum eq 24940) or (ip.geoip.asnum eq 12824) or (ip.geoip.asnum eq 60068) or (ip.geoip.asnum eq 8374) or (ip.geoip.asnum eq 42116) or (ip.geoip.asnum eq 23944) or (ip.geoip.asnum eq 9318) or (ip.geoip.asnum eq 46573) or (ip.geoip.asnum eq 8400) or (ip.geoip.asnum eq 7713) or (ip.geoip.asnum eq 30083) or (ip.geoip.asnum eq 35393) or (ip.geoip.asnum eq 29182) or (ip.geoip.asnum eq 23671) or (ip.geoip.asnum eq 8151) or (ip.geoip.asnum eq 26347) or (ip.geoip.asnum eq 2116) or (ip.geoip.asnum eq 46606) or (ip.geoip.asnum eq 12695) or (ip.geoip.asnum eq 29017) or (ip.geoip.asnum eq 45289) or (ip.geoip.asnum eq 24971) or (ip.geoip.asnum eq 32244) or (ip.geoip.asnum eq 133479) or (ip.geoip.asnum eq 23647) or (ip.geoip.asnum eq 11340) or (ip.geoip.asnum eq 47521) or (ip.geoip.asnum eq 62729) or (ip.geoip.asnum eq 135905) or (ip.geoip.asnum eq 45352) or (ip.geoip.asnum eq 7488) or (ip.geoip.asnum eq 18229) or (ip.geoip.asnum eq 36352) or (ip.geoip.asnum eq 63760) or (ip.geoip.asnum eq 46606) or (ip.geoip.asnum eq 131386) or (ip.geoip.asnum eq 197309) or (ip.geoip.asnum eq 16347) or (ip.geoip.asnum eq 12576) or (ip.geoip.asnum eq 22611) or (ip.geoip.asnum eq 56150) or (ip.geoip.asnum eq 59491) or (ip.geoip.asnum eq 23671) or (http.request.uri contains "/wp-login.php") or (ip.geoip.country eq "JP") or (ip.geoip.country eq "IL") or (ip.geoip.asnum eq 49981) or (ip.geoip.asnum eq 9009) or (ip.geoip.asnum eq 56522) or (ip.geoip.asnum eq 196777) or (ip.geoip.asnum eq 4837)

La segunda regla es

(ip.geoip.asnum eq 4837) or (ip.geoip.asnum eq 43350) or (ip.geoip.asnum eq 51448) or (ip.geoip.asnum eq 204490) or (ip.geoip.asnum eq 56534) or (ip.geoip.asnum eq 29550) or (ip.geoip.asnum eq 18978) or (ip.geoip.asnum eq 208294) or (ip.geoip.asnum eq 205100) or (ip.geoip.asnum eq 396507) or (ip.geoip.asnum eq 208323) or (ip.geoip.asnum eq 20845) or (ip.geoip.asnum eq 31103) or (ip.geoip.asnum eq 49447) or (ip.geoip.asnum eq 1101) or (ip.geoip.asnum eq 4224) or (ip.geoip.asnum eq 6830) or (ip.geoip.asnum eq 209) or (ip.geoip.asnum eq 34665) or (ip.geoip.asnum eq 61317) or (ip.geoip.asnum eq 395111) or (ip.geoip.asnum eq 43289) or (ip.geoip.asnum eq 44220) or (ip.geoip.asnum eq 202425) or (ip.geoip.asnum eq 62468) or (ip.geoip.asnum eq 173) or (ip.geoip.country eq "T1") or (ip.geoip.asnum eq 213371)
La configuración de las reglas y el orden debe quedar similar a esta imagen.

Al revisar el registro del firewall, pude ver que las reglas bloquean de manera satisfactoria los intentos de ataque.

Ejemplo de una solicitud fraudulenta que fue bloqueada por medio de Desafío (CAPTCHA)

La imagen anterior es un ejemplo de una solicitud que fue interceptada por el firewall. La razón del bloqueo fue porque la solicitud provenía de la red OVH que se encuentra en la regla Challenge 1. Podemos ver que la solicitud es en efecto fraudulenta porque intenta acceder a un archivo PHP dentro de un plugin de gestión de archivos.

Con estas simples acciones hemos añadido una capa de protección efectiva a nuestro sitio en WordPress. Y lo mejor es que es compatible con todas las demás plataformas.


Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

%d