¿No sabes qué significa algún término? Consulta el glosario
Cómo proteger WordPress gratis y sin plugins
Los plugins de seguridad en WordPress son bloatware con una aureola: ralentizan todo y venden comodidad, no protección. Wordfence, All-In-One Security, Solid Security, Sucuri… Son todos innecesarios y no necesitas instalar ninguno.
Sin embargo, como vender seguridad siempre funciona, incluso cuando es principalmente un placebo, son muy populares. Demasiados desarrolladores y supuestos expertos te recomiendan usar uno. Bueno, pues no lo hagas.
Por qué los plugins de seguridad son malos para el rendimiento
En general, cada vez que un usuario solicita una página, WordPress necesita ejecutar operaciones costosas en términos de tiempo de ejecución: WordPress ejecuta su código PHP, que ejecuta el código de cada plugin, y esos plugins a menudo también consultan la base de datos.
Cuando instalas un plugin de seguridad, WordPress también tiene que ejecutar el código de dicho plugin que gestiona todas las funciones que promociona:
- Cortafuegos
- Protección contra fuerza bruta
- Detección de cambios de archivos
- Escáner de malware
- Seguridad de inicio de sesión
- Registros de actividad
- Protección contra bots
- Otras pequeñas herramientas de seguridad
Casi todas, o todas estas funciones deben ejecutarse por cada solicitud. Esto tiene un coste, y aquí puedes leer exactamente cuál es.
No digo que debas ignorar la seguridad. Al contrario, es super-importante hoy en día. Sin embargo, idealmente, la seguridad debería implementarse a nivel de servidor o CDN, de modo que, cuando alguien sin buenas intenciones intente acceder a tu sitio, sea bloqueado antes de que consuma los recursos del servidor ejecutando el código de la aplicación (WordPress).
Ilustremos esto con un ejemplo. Pero primero, para visualizar cómo funciona el flujo de solicitudes de una web típica, dale un vistazo a este diagrama:

Ahora, imaginemos una empresa en Alemania que atiende exclusivamente a clientes alemanes. Imaginemos a un usuario o bot vietnamita intentando iniciar sesión como administrador solo para instalar malware.
Esto es lo que sucede cuando confías en un plugin de seguridad:
- El usuario (o bot) escribe
https://ejemplo.com/wp-login.phpen la barra de direcciones. - La solicitud pasa a través de la CDN.
- La solicitud llega al servidor.
- El servidor web pasa la solicitud a WordPress.
- WordPress ejecuta su código central.
- WordPress ejecuta todo el código de los plugins.
- El plugin de seguridad procesa la solicitud y decide bloquearla.
- Se le indica a WordPress que responda con una página de bloqueo, una página 404 u otra respuesta configurada.
- WordPress debe generar esa página. Si usas un maquetador de páginas, también lo carga. Si no, sigue dependiendo del editor de bloques (Gutenberg).
Ahora compara esto con manejar la seguridad adecuadamente configurando tu CDN en lugar de instalar un plugin de seguridad:
- El usuario (o bot) escribe
https://ejemplo.com/wp-login.phpen la barra de direcciones. - La solicitud llega a la CDN.
- La CDN bloquea la solicitud, por ejemplo, porque no se permite el tráfico vietnamita.
- WordPress nunca se ejecuta y los recursos del servidor permanecen disponibles para los usuarios de verdad.
Imaginemos esto con miles de solicitudes de este tipo ocurriendo simultáneamente en cuestión de segundos, algo muy común cuando hay bots involucrados (bots siendo bots). Como dijimos, al implementar la seguridad correctamente, a nivel de CDN o servidor, nos ahorramos una cantidad importante de recursos del servidor (CPU, RAM…).
Los complementos de seguridad no te protegen de las amenazas reales
Thomas J. Raef es el fundador de We Watch Your Website, una empresa que ha eliminado malware de sitios web desde 2007. Participó en un podcast de WP Tavern para hablar sobre seguridad y cómo los sitios web son hackeados. Según él, las verdaderas amenazas a las que se enfrenta un sitio web de WordPress son:
- Nombres de usuario y contraseñas comprometidos
- Vulnerabilidades en complementos y temas
- Cookies de sesión robadas
Esto significa que siempre que utilices contraseñas seguras y únicas, mantengas todos los plugins y temas actualizados, evites instalar aplicaciones, plugins o programas sospechosos en tu ordenador o web, y no descargues nada de fuentes desconocidas o no confiables, el 90% del trabajo ya estará hecho.
¿Pero qué pasa con el 10% restante?
Cómo proteger realmente tu sitio WordPress sin ralentizarlo
Veamos todas las medidas que puedes tomar para proteger tu web de amenazas reales sin usar plugins y manteniendo la mayor cantidad posible de funciones de seguridad fuera de la capa de aplicación. El objetivo es evitar que WordPress desperdicie recursos en tareas no relacionadas con responder a una solicitud de una página; es decir, detener a los actores malintencionados antes de que lleguen a WordPress, a nivel de servidor o CDN.
Este artículo se estructura en tres partes: consejos esenciales de seguridad para WordPress, reglas de seguridad de Cloudflare y reglas de .htaccess. Verás que muchas de las reglas de Cloudflare y .htaccess comprueban la cookie de inicio de sesión o el agente de usuario de la solicitud. Sé que tanto la cookie como el agente de usuario se puede falsificar fácilmente. Estas reglas de Cloudflare y .htaccess que mencionaré se dirigen principalmente a scripts automatizados ejecutados por bots, que rara vez se molestan en realizar ataques más sofisticados enviando cookies o modificando los detalles de la solicitud. Un usuario que realmente quiera atacar tu sitio podrá eludir fácilmente estas reglas, por lo que es fundamental seguir los consejos de seguridad esenciales a continuación.
Consejos esenciales de seguridad para WordPress
Lo primero y más importante son algunos consejos y ajustes básicos para WordPress que todos deberíamos conocer y tener en cuenta.
1) Mantén WordPress, tu tema y todos tus plugins actualizados
Esto es extremadamente importante. Como he mencionado antes, las versiones sin actualizar son a menudo peligrosas, y tener un solo plugin desactualizado es suficiente para que un usuario malintencionado acceda a tu web a través de una vulnerabilidad de seguridad. Esto también incluye plugins de pago o premium con licencias caducadas que ya no se pueden actualizar. Si tienes alguno de estos plugins y no quieres renovar la licencia, es mejor buscar una alternativa.
2) No descargues plugins de pago de fuentes no oficiales
Todas esas versiones «crackeadas» de plugins de pago son muy peligrosas, ya que no hay ninguna garantía de que estén libres de malware. De hecho, siempre deberías asumir que las descargas no oficiales han sido comprometidas. Por favor, apoya a los desarrolladores y usa el método oficial para acceder a las funciones que necesitas 🙂
3) Utiliza contraseñas seguras y únicas
Sí, sé que las contraseñas son molestas. Pero es necesario que lo sean, de lo contrario, alguien más podría acceder fácilmente a tu cuenta. Nunca uses contraseñas débiles como «123456», «admin123» o tu fecha de nacimiento. Cuanto más compleja sea la contraseña, mejor. Y nunca uses la misma contraseña en diferentes servicios. Usa una contraseña para tu cuenta de administrador, otra para tu proveedor de alojamiento, otra para tu cuenta FTP, otra para tu base de datos, etc.
4) No utilices el nombre de usuario “admin”
Esto ayuda a prevenir ataques de fuerza bruta que apuntan específicamente a nombres de usuario comunes como «admin» y «administrador», que a menudo son los nombres de usuario por defecto en las instalaciones automáticas de WordPress.
5) Protege tu página de inicio de sesión
La página wp-login.php es probablemente la más atacada por ataques de fuerza bruta. Por lo tanto, conviene protegerla.
La opción que más recomiendo es simplemente cambiar la URL de la página de inicio de sesión, por ejemplo a https://dominio.com/loginpersonalizado. Si no hay un punto de entrada conocido, los atacantes ni siquiera pueden iniciar un ataque de fuerza bruta.
El mejor plugin para cambiar la URL de inicio de sesión es el ligero WPS Hide Login. Hace esta tarea sin nada de características innecesarias. Sin embargo, probablemente también te interese optimizar tu sitio. En este caso, te recomendaría Perfmatters, que ya incluye esta función.
Otra opción que se menciona es instalar un plugin para limitar los intentos de inicio de sesión y evitar ataques de fuerza bruta. Aunque es mejor que nada, sigo prefiriendo ocultar la página de inicio de sesión. Al ocultarla, puedes directamente bloquear wp-login.php a nivel de servidor o CDN, lo que garantiza que las solicitudes maliciosas ni siquiera afecten a WordPress. Por el contrario, al solo limitar los intentos de inicio de sesión, cada solicitud hace que WordPress ejecute todo el código PHP, incluido el del plugin, y realice consultas a la base de datos para determinar si la solicitud debe bloquearse. Si, a pesar de todo, prefieres usar un plugin para limitar los intentos de inicio de sesión, evita el famoso plugin Limit Login Attempts Reloaded: una alternativa más ligera es Loginizer.
6) Utiliza 2FA
Me encanta el plugin oficial Two Factor porque es ligero, compatible con las principales aplicaciones de autenticación, y no tiene molestos anuncios de versiones de pago. Sí, sé que he dicho que no necesitarías plugins, pero instalar este no te hará daño, ¡te lo prometo!
¡Gracias a Willem de Zoete por la sugerencia!
7) Algunos ajustes más (opcionales)
Los seis puntos anteriores cubren los consejos de seguridad más básicos para proteger tu sitio web. Antes de pasar a la siguiente sección, te recomiendo leer este artículo de Vladimir Smitka. Explica varias maneras adicionales de reforzar tu instalación de WordPress, y no son las típicas sugerencias que encontrarás en otros artículos optimizados para SEO, ¡así que léelo!
Cloudflare
Bien, vayamos a la parte divertida. Has aplicado los consejos básicos de seguridad, pero te gustaría estar aún mejor protegido. ¡No instales ningún plugin de seguridad! Solo necesitas Cloudflare y su plan gratuito. Primero, si no tienes una cuenta, crea una y asegúrate de que tu web esté ya configurada. Hay muchas guías disponibles, así que no dudes en buscarlas.
Nota: Los textos de las fotos que verás aquí están en inglés. La traducción al español de Cloudflare no es muy buena ni consistente. De hecho, te animo a que cambies el idioma de Cloudflare al inglés completamente.
Una vez que tu sitio web esté en Cloudflare, es hora de aplicar las reglas de seguridad y de limitación de tasa. Estas reglas son fáciles de entender, pero un poco complicadas de configurar, que es lo que te enseñaré aquí. Las reglas son un conjunto de instrucciones que le das a Cloudflare para indicarle qué hacer con las solicitudes que cumplen ciertas condiciones. Por ejemplo, puedes decir fácilmente: «Bloquear todas las solicitudes que provengan de Vietnam».
Si aún no estás en tu cuenta de Cloudflare, inicia sesión y ve a Security > Security rules.

0) IP y servicios permitidos
Este paso preliminar también implica, técnicamente, crear una regla de seguridad, pero en lugar de bloquear el tráfico, debemos permitirlo. ¿Por qué? Porque si simplemente creas reglas de seguridad de bloqueo, también podrías bloquear servicios legítimos como rastreadores de motores de búsqueda, plugins, etc.
Haz clic en + Create rule y añade una nueva Custom rule. Asígnale un nombre, como «IP y servicios permitidos», y empieza a rellenar los campos.
- Field: corresponde a la parte de la solicitud que Cloudflare evalúa (IP, agente de usuario, ruta URI…).
- Operator: La lógica de comparación utilizada para evaluer el campo (igual a, contiene, mayor que…).
- Value: Los datos específicos con los que se compara el campo.
Por ejemplo, supongamos que usas ShortPixel como plugin de optimización de imágenes, SendGrid para gestionar tus correos electrónicos y listas, y WP Rocket como plugin de caché. Necesitarás averiguar todas las IP que usa ShortPixel y en los casos en que las IP no sean públicas, como con SendGrid y WP Rocket, puedes identificar estas solicitudes por su agente de usuario. Luego, añádelas así:

O puede copiar y pegar la siguiente expresión en el editor de expresiones:
(http.user_agent contains "WP-Rocket") or (http.user_agent contains "WP Rocket") or (http.user_agent contains "SendGrid Event API") or (ip.src eq 136.243.103.55) or (ip.src eq 176.9.77.187) or (ip.src eq 176.9.21.94)
Recuerda que tendrás que editarla y modificar todos los valores, añadir o eliminar algunos de ellos, dependiendo de a qué necesite acceder tu web.
Desplázate hacia abajo y en Choose action, selecciona «Skip», deja activado «Log matching requests» y selecciona todos los WAF components to skip a continuación:

En palabras sencillas, esta regla significa:
- Si la solicitud entrante proviene de un agente de usuario que contiene
WP-Rocket, - o un agente de usuario que contiene
WP Rocket, - o un agente de usuario que contiene
SendGrid Event API, - o desde la IP
136.243.103.55, - o desde la IP
176.9.77.187, - o desde la IP
176.9.21.94, - omite todos los componentes del firewall y permite la solicitud.
Guarda la regla y cree la siguiente.
1) Bloquear solicitudes maliciosas
Es hora de bloquear a los «hackers» malos (normalmente bots). Asigna a esta custom rule un nombre como «WordPress – Bloquear solicitudes maliciosas» y añade la siguiente expresión con el editor de expresiones:
(http.request.uri.path wildcard r"*/admin/*" and not http.cookie contains "wordpress_logged_in") or (http.request.uri.path wildcard r"*wlwmanifest*") or (starts_with(http.request.uri.path, "/.") and not cf.client.bot and not starts_with(http.request.uri.path, "/.well-known")) or (http.request.uri.path wildcard r"*/xmlrpc.php") or (http.request.uri.path wildcard r"*/wp-json/*" and not http.cookie contains "wordpress_logged_in" and not http.request.uri.path contains "wp-json/wp/v2/search" and not cf.client.bot) or (starts_with(http.request.uri.path, "/wp-") and ends_with(http.request.uri.path, "/") and not ends_with(http.request.uri.path, "wp-admin/") and not http.request.uri.path contains "wp-json") or (http.request.uri.query eq "action=register") or (http.request.method eq "GET" and ends_with(http.request.uri.path, ".php") and http.request.uri.path ne "/index.php" and http.request.uri.path ne "/wp-login.php" and http.request.uri.path ne "/wp-cron.php" and not http.cookie contains "wordpress_logged_in")
La acción que debes realizar para esta regla es «Block», así de simple. Y es muy importante que se añada debajo de la regla «IP y servicios permitidos» . De lo contrario, no se incluirán en la lista blanca porque se bloquearán antes de que alcancen la regla. Así es como debería verse la regla:

Analicemos cada condición de la regla.

Esto bloquea todas las solicitudes de usuarios desconectados a cualquier ruta que contenga /admin/. Los bots intentan acceder muchas veces a este tipo de URL.
Advertencia: algunos temas o maquetadores, como Divi, almacenan ciertos recursos en una carpeta llamada admin, por lo que si notas problemas, elimina esta condición.

Esta es sencilla. El enlace wlwmanifest lo usaba Windows Live Writer, que seguro ya no usas, y sigue siendo objetivo de ataques. Esta condición bloquea todas las solicitudes a cualquier ruta que contenga wlwmanifest.

Los bots también atacan archivos y carpetas como /.env o /.git/config ya que suelen exponer secretos de alto valor o detalles internos de la aplicación al acceder accidentalmente a ellos en un servidor web. En un sitio web normal de WordPress, estos no existen. De hecho, solo hay un archivo y una carpeta que empiezan por /.: el archivo .htaccess, que no debería ser de acceso público, y la carpeta .well-known, que sí lo es y debería ser accesible para la verificación de certificados SSL y para el archivo security.txt. Por eso, esta condición bloquea todas las solicitudes a /. excepto cuando se trata de un bot conocido e inofensivo o cuando la solicitud se dirige a una subcarpeta o archivo dentro de /.well-known.

xmlrpc.php es un endpoint fundamental de WordPress que implementa el protocolo XML-RPC, permitiendo que sistemas remotos interactúen con un sitio de WordPress sin usar la interfaz web. Históricamente, era la API principal antes de la existencia de la API REST moderna, y xmlrpc.php sigue siendo un archivo objetivo frecuente de ataques porque a veces todavía se utiliza, especialmente por el plugin Jetpack.
Advertencia: Es muy probable que puedas dejar esta condición en funcionamiento sin problemas. Sin embargo, si sabes que un plugin de tu sitio usa el protocolo XML-RPC, elimina esta condición de la regla de seguridad para que estas solicitudes puedan pasar por Cloudflare. O mejor aún, deja el bloqueo activado y añade a la lista blanca de arriba los servicios que lo necesiten.

Esta condición bloquea el acceso anónimo a la API REST de WordPress, es decir, las solicitudes a la ruta /wp-json/, pero permite a los usuarios conectados, ya que el lado de administración llama constantemente a /wp-json/. También permite que la funcionalidad de búsqueda siga funcionando. Y por si acaso, también impide el bloqueo de los bots verificados conocidos.
Advertencia: La API REST se usa ampliamente. Muchos plugins y servicios dependen de ella para recuperar información y proporcionar funcionalidad. Por ejemplo, WooCommerce realiza solicitudes a /wp-json/wc/, Contact Form 7 a /wp-json/contact-form-7/, y Events Manager a /wp-json/events-manager/. Debes incluir todos estos en tu condición. De lo contrario, es muy probable que el plugin o servicio correspondiente deje de funcionar.

A los bots les encanta buscar carpetas de WordPress expuestas, dirigiéndose a todos los directorios y subdirectorios predeterminados de WordPress. Esta condición bloquea todas las solicitudes cuya ruta empieza por /wp- y termina con una barra diagonal final, como /wp-includes/ o /wp-content/uploads/, y excluye el área de administración (/wp-admin/) y la API REST (/wp-json/). Ningún usuario normal solicitaría directamente un directorio como este, por lo que debería ser relativamente seguro bloquearlos.

Al activar el ajuste de WordPress «Cualquiera puede registrarse», una nueva URL estará disponible para todos: https://tudominio.com/wp-login.php?action=register. Sin embargo, muy pocas personas usan la página de registro por defecto de WordPress, y muchos sitios no permiten el registro de usuarios. Aun así, los bots atacan tal URL de registro.
Advertencia: No añadas esta condición si esta página está destinada a uso público (https://tudominio.com/wp-login.php?action=register), o si tienes alguna página que utiliza el parámetro action=register, de lo contrario no funcionará.

Finalmente, tenemos una condición dirigida a personas o bots que no han iniciado sesión e intentan cargar directamente archivos .php arbitrarios. Esto casi nunca es un comportamiento normal y suele ser señal de intentos de sondeo o malintencionados. En teoría, /index.php, /wp-login.php y /wp-cron.php son los únicos archivos PHP que un usuario que no ha iniciado sesión debería solicitar directamente con una solicitud GET. Las solicitudes POST son comunes entre los visitantes reales, por lo que bloquearlas sería un error. Además, casi todas las páginas del área de administración son solicitudes GET a un archivo PHP, como https://www.asistentewp.com/wp-admin/edit.php, por lo que esta condición solo se dirige a solicitudes GET de invitados.
Advertencia: Revisa la funcionalidad de tu sitio como visitante sin conectarse, ya que algunas funciones podrían dejar de funcionar. Por ejemplo, al cambiar la dirección de correo electrónico del administrador, WordPress envía un enlace de confirmación a la nueva dirección que apunta a profile.php, como https://www.dominio.com/wp-admin/profile.php?newuseremail=9dcd1943c534457b9e8cd9307c7fd17d. Si abres ese enlace en un navegador sin haber iniciado sesión, la solicitud se bloqueará porque profile.php no se encuentra entre las páginas permitidas para usuarios no conectados. En este caso, simplemente asegúrate de haber iniciado sesión antes de abrir el enlace.
Si descubre que se debe acceder a otras páginas PHP sin iniciar sesión, simplemente añádelas a la condición.
2) Desafío administrado (Managed Challenge)
Hay algunas solicitudes que no se pueden bloquear directamente, como las de la regla anterior, ya que bloquearían visitas o solicitudes legítimas. Basta con observar todas las excepciones de las que ya he hablado arriba. Sin embargo, con Cloudflare podemos añadir el conocido desafío administrado (en inglés Managed Challenge), que es la típica pantalla de «¿Eres humano?», para aquellas solicitudes que no se pueden bloquear directamente y que no se realizan en segundo plano, ya que un desafío bloquearía estas:

Crea una nueva custom rule, llámala «WordPress – Desafío administrado» y añade la siguiente expresión usando el editor de expresiones:
(http.request.uri.path wildcard r"*/wp-login.php") or (http.request.uri.query wildcard r"*author=*") or (http.request.uri.path wildcard r"*.txt" and http.request.uri.path ne "/robots.txt" and not cf.client.bot and not starts_with(http.request.uri.path, "/.well-known")) or (not ip.src.country in {"IL" "ES"} and not cf.client.bot and not starts_with(http.request.uri.path, "/.well-known") and ip.src.asnum ne 13335)
La acción que debes seleccionar para esta regla es «Desafío administrado», y de nuevo es muy importante que se añada debajo de la regla «IP y servicios permitidos». Debería verse así:

Analicemos también cada condición de la regla.

Esta es la más sencilla. Nadie más a parte de ti y tus usuarios registrados necesita acceder a tu página de inicio de sesión. Por lo tanto, debes mantener a raya a los bots colocando la página wp-login.php tras un desafío administrado.
Si cambias tu página de inicio de sesión, puedes añadir esta condición a la regla de bloqueo anterior en lugar de aquí, ya que en ese caso nadie necesitará acceder a wp-login.php. También deberás añadir tu nueva página de inicio de sesión a esta regla de desafío administrado, reemplazando wp-login.php.

Un ataque común en WordPress es la enumeración de usuarios, ya que es una forma muy rápida de identificar a los usuarios de una instalación de WordPress. Pruébalo tú mismo. Accede a tudominio.com/?author=1 y probablemente llegarás a una página de autor que revela un nombre de usuario. El ataque es simple. Simplemente escanea la página de inicio con la cadena de consulta author=1, author=2, author=3, etc., y obtendrás una lista de todos los usuarios para intentar forzar sus contraseñas. Este escaneo casi siempre lo realizan scripts y bots, así que solo necesitas indicarle
a Cloudflare que revise cada URL que contenga la cadena de consulta author=. Y ahora puedes seguir mostrando la página de autor y evitar esos molestos ataques.

Los bots que intentan encontrar archivos expuestos también intentarán localizar archivos .txt, que suelen proporcionar información sobre las versiones exactas de varios plugins, como changelog.txt o readme.txt. Por lo tanto, para la mayoría de los sitios, debería ser seguro
desafiar todas las solicitudes de archivos .txt, a menos que la solicitud sea para robots.txt, provenga de un bot verificado o tenga como objetivo la carpeta /.well-known, a la que accede habitualmente Let’s Encrypt, por ejemplo.

Todas las condiciones son opcionales, pero esta lo es aún más, si es que eso tiene sentido. Se trata simplemente de un bloqueo por país. Si tu sitio web solo es para clientes de España, ¿por qué debería tu servidor desperdiciar recursos con otros países, especialmente países como Vietnam, China o Rusia, de donde proviene la mayor parte del spam?
En este ejemplo en particular, básicamente estamos desafiando cualquier solicitud que no provenga de Israel o España, a menos que provenga de un bot conocido, se dirija a la carpeta /.well-know o provenga del sistema autónomo 13335, que es propiedad de Cloudflare y se utiliza, por ejemplo, al usar su chat de soporte con IA, que de otro modo no podría acceder a tu sitio para solucionar problemas.
Advertencia: Debes personalizar esta condición según los países de donde provengan tus clientes o visitantes, o eliminarla por completo si tu tráfico es internacional.
3) Limitación de tasa
Finalmente, debemos abordar las solicitudes que logran eludir las dos reglas anteriores. Nunca será posible bloquear el 100 % de las solicitudes maliciosas, pero sí que podemos limitar su frecuencia. Ocasionalmente, un bot puede lanzar cientos de solicitudes en cuestión de segundos, lo que puede sobrecargar el servidor, dependiendo de la magnitud del ataque. A veces, ni siquiera es un bot malo, lo he visto personalmente con rastreadores de Meta y Microsoft, que ocasionalmente se descontrolan y prueban muchísimas diferentes combinaciones de URL, haciendo que las webs se caigan.
Añade una nueva Rate limiting rule, no una custom rule, y nómbrala, por ejemplo, «Protección DDOS básica de WordPress». Luego, añade la siguiente expresión:
(not http.request.uri.path contains "/wp-" and not cf.bot_management.verified_bot) or (http.request.uri.path wildcard r"/wp-content/themes/*/style*.css" and not cf.bot_management.verified_bot) or (cf.verified_bot_category eq "AI Crawler")
Desplázate hacia abajo y, en la sección «When rate exceeds…», empieza con 10 solicitudes cada 10 segundos. Es casi imposible que una persona visite más de 10 páginas en 10 segundos o menos. La acción que debes elegir es «Block» durante 10 segundos. Debería verse así:

Revisemos las condiciones de la regla con más detalle.

No podemos limitar la tasa de cada una de las solicitudes, ya que al visitar una página, no solo se solicita la página en sí, sino también todos los recursos estáticos enlazados desde el HTML. Afortunadamente, estos recursos casi siempre se encuentran en una de las carpetas /wp- (wp-content, wp-includes y wp-admin). Por eso, al excluir la cadena /wp-, limitamos la regla de limitación de tasa a las solicitudes de URL normales, por ejemplo dominio.com/esto-es-un-post. También excluimos bots verificados, como Googlebot, por si acaso.

De la misma manera que los bots intentan rastrear varios archivos .txt, también intentan acceder a los archivos de estilo de temas, que casi siempre se encuentran en /wp-content/themes/nombre_del_tema/style.css. Suponemos que esto se hace para determinar si existe un tema específico y, de ser así, aprovechar sus posibles vulnerabilidades.
Idealmente, desafiaríamos estas solicitudes. Sin embargo, los visitantes también acceden a estos archivos. Si los desafiáramos, la página aparecería sin estilo porque los archivos de estilo del tema no se cargarían, ya que Cloudflare los estaría desafiando en segundo plano. Por lo tanto, lo único que podemos hacer es limitar la tasa de estas solicitudes para que los visitantes reales puedan acceder a ellas, mientras que los ataques no hagan daño.
También excluimos los bots verificados para que estas solicitudes no cuenten para el umbral de limitación de tasa y no se bloqueen innecesariamente.

Los rastreadores de IA pueden ser una pesadilla cuando deciden rastrear un sitio web completo. Dado que su función es exclusivamente de entrenamiento de IA, tiene sentido limitarlos: no hay problema si usan nuestro contenido y nos hacen referencia, pero no a cualquier precio.
¿No tienes Cloudflare? Puedes usar el archivo .htaccess
La opción número uno que recomiendo es usar Cloudflare porque es muy flexible y las solicitudes ni siquiera afectan a tu sitio. Te ahorrará muchos dolores de cabeza.
Sin embargo, si no quieres o no puedes usar Cloudflare y usas Apache o LiteSpeed como servidor web, puedes añadir algunas reglas de seguridad al archivo .htaccess que imitarán lo que hacíamos en Cloudflare. No todas, ya que el archivo .htaccess no es tan flexible y no puede limitar la tasa ni determinar qué solicitudes provienen de un bot conocido, por ejemplo.
Continúa y abre tu archivo .htaccess, ubicado en la raíz de tu sistema de archivos, y añade lo siguiente al comienzo del archivo.
<IfModule mod_rewrite.c>
# Block arbitrary PHP files in site (GET only)
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_ [NC]
RewriteCond %{REQUEST_METHOD} =GET [NC]
RewriteCond %{REQUEST_URI} \.php$ [NC]
RewriteCond %{REQUEST_URI} !^/(index|wp-login|wp-cron)\.php$ [NC]
RewriteCond %{REQUEST_URI} !^/wp-admin/ [NC]
RewriteRule .* - [F]
# Block wlwmanifest always
RewriteCond %{REQUEST_URI} (wlwmanifest|xmlrpc\.php) [NC]
RewriteRule .* - [F]
# Block directory-style access to /wp-* paths
RewriteCond %{REQUEST_URI} ^/wp- [NC]
RewriteCond %{REQUEST_URI} /$
RewriteCond %{REQUEST_URI} !^/wp-admin/ [NC]
RewriteCond %{REQUEST_URI} !wp-json [NC]
RewriteRule .* - [F]
# Block /wp-json/ (except /wp-json/oembed/1.0/embed and wp-json/wp/v2/search) unless user is logged in
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_ [NC]
RewriteCond %{REQUEST_URI} ^/wp-json/ [NC]
RewriteCond %{REQUEST_URI} !^/wp-json/oembed [NC]
RewriteCond %{REQUEST_URI} !^/wp-json/wp/v2/search [NC]
RewriteRule .* - [F]
# Block User ID Phishing Requests
RewriteCond %{QUERY_STRING} (author=\d+|action=register) [NC]
RewriteRule .* - [F]
# Protect login/admin POST requests from off-site sources
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} ^/wp-login\.php$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://([^/]+\.)?domain\.com [NC]
RewriteRule .* - [F]
</IfModule>
Repasemos nuevamente todos los bloques de código.
# Block arbitrary PHP files in site (GET only)
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_ [NC]
RewriteCond %{REQUEST_METHOD} =GET [NC]
RewriteCond %{REQUEST_URI} \.php$ [NC]
RewriteCond %{REQUEST_URI} !^/(index|wp-login|wp-cron)\.php$ [NC]
RewriteCond %{REQUEST_URI} !^/wp-admin/ [NC]
RewriteRule .* - [F]
Este bloque de código impide cualquier intento de abrir archivos .php aleatorios, de la misma forma que lo hicimos con una de las condiciones de Cloudflare. Se bloquea cualquier solicitud GET de un archivo .php que no provenga de un usuario conectado (cookie wordpress_logged_in_) y que no sea index.php, wp-login.php o wp-cron.php, que son los únicos que deben solicitarse desde la vista pública.
La condición adicional RewriteCond %{REQUEST_URI} !^/wp-admin/ [NC] excluye la ruta /wp-admin/ de este bloqueo. Esto se añade porque Apache puede realizar solicitudes GET a archivos .php dentro de /wp-admin/ durante operaciones normales del panel de administración, incluso para usuarios que todavía no son reconocidos como conectados por esta regla. Sin esta exclusión, tu página de inicio de sesión podría simplemente no funcionar.
En OpenLiteSpeed, esta exclusión no es necesaria porque su manejo de reglas de reescritura funciona de manera diferente y no provoca este mismo comportamiento. Sin embargo, en Apache garantiza que el área de administración siga funcionando correctamente mientras se sigue bloqueando el acceso directo a archivos PHP aleatorios en otras partes del sitio.
# Block wlwmanifest and xmlrpc.php always
RewriteCond %{REQUEST_URI} (wlwmanifest|xmlrpc\.php) [NC]
RewriteRule .* - [F]
Aquí bloqueamos todos los intentos de acceder a cualquier URL que contenga las cadenas wlwmanifest, utilizadas por Windows Live Writer y casi completamente inútiles, o xmlrpc.php, utilizadas para el protocolo XML-RPC y comúnmente explotadas.
Advertencia: Es muy probable que puedas dejar esta regla sin cambios, pero si sabes que un plugin de tu web usa el protocolo XML-RPC, elimina esta condición para que las solicitudes puedan procesarse. La línea quedaría así:RewriteCond %{REQUEST_URI} wlwmanifest [NC]
# Block directory-style access to /wp-* paths
RewriteCond %{REQUEST_URI} ^/wp- [NC]
RewriteCond %{REQUEST_URI} /$
RewriteCond %{REQUEST_URI} !^/wp-admin/ [NC]
RewriteCond %{REQUEST_URI} !wp-json [NC]
RewriteRule .* - [F]
Estas son las reglas que bloquean las búsquedas de directorios expuestos que realizan los bots, es decir, rutas que empiezan /wp- y terminan con /, como midominio.com/wp-includes/ o midominio.com/wp-content/uploads/2023/. También se excluyen las páginas de administración, ubicadas en /wp-admin/, y la API REST, que contiene wp-json en la solicitud de URL.
# Block /wp-json/ (except /wp-json/oembed/1.0/embed and wp-json/wp/v2/search) unless user is logged in
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_ [NC]
RewriteCond %{REQUEST_URI} ^/wp-json/ [NC]
RewriteCond %{REQUEST_URI} !^/wp-json/oembed [NC]
RewriteCond %{REQUEST_URI} !^/wp-json/wp/v2/search [NC]
RewriteRule .* - [F]
Esta regla intenta bloquear las solicitudes no autorizadas de la API REST, a la que la parte de /wp-json/ se refiere. Normalmente, solo los servicios externos necesitan acceder a ella. Emulando la misma regla que expliqué anteriormente para Cloudflare, en este orden indicamos:
- Si un usuario no ha iniciado sesión (cookie
wordpress_logged_in_), - y solicita una URL que contiene la ruta
/wp-json/, - y no es
/wp-json/oembed(no podemos detectar bots conocidos y, por lo tanto, deberíamos permitir solicitudes de vistas previas de enlaces en Facebook, LinkedIn y plataformas similares que usan este endpoint, por ejemplo), - y no es
/wp-json/wp/v2/search(a veces se usa para búsquedas, como con el tema Blocksy), - bloquéalo.
Advertencia: La API REST se usa ampliamente. Muchos plugins y servicios dependen de ella para recuperar información y proporcionar funcionalidad. Por ejemplo, WooCommerce realiza solicitudes a /wp-json/wc/, Contact Form 7 a /wp-json/contact-form-7/, y Events Manager a /wp-json/events-manager/. Debes incluir todos estos como excepciones también. De lo contrario, es muy probable que el plugin o servicio correspondiente deje de funcionar. Por ejemplo, si necesitas que WooCommerce esté permitido, añade esta línea debajo de la línea de búsqueda:RewriteCond %{REQUEST_URI} !^/wp-json/wc [NC]
# Block User ID Phishing Requests
RewriteCond %{QUERY_STRING} (author=\d+|action=register) [NC]
RewriteRule .* - [F]
En este caso, bloqueamos todos los intentos de descubrir todos los nombres de usuario en un sitio cuando los bots intentan acceder a cadenas de consulta author=X, conocido como enumeración de usuarios, o cuando intentan acceder a la página de registro predeterminada utilizando la cadena de consulta action=register.
Advertencia: No añadas esta condición si necesitas que estas URL sean de acceso público:
– https://tudominio.com/wp-login.php?action=register
– https://tudominio.com/?author=X (donde X es un número).
Si solo una de ellas necesita estar disponible, elimina la otra de la regla. Por ejemplo:RewriteCond %{QUERY_STRING} author=\d+ [NC]
# Protect login/admin POST requests from off-site sources
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} ^/wp-login\.php$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://([^/]+\.)?domain\.com [NC]
RewriteRule .* - [F]
Y finalmente, llegamos a la regla de seguridad que mola más. Su propósito es bloquear intentos de inicio de sesión sospechosos. Primero verifica si el método de solicitud es POST, lo que significa que alguien está enviando datos (como un formulario de inicio de sesión). Luego confirma que la solicitud se dirige a /wp-login.php, que es el endpoint de inicio de sesión de WordPress. A continuación, examina la cabecera HTTP_REFERER y se asegura de que la solicitud se originó desde el mismo dominio (domain.com o cualquiera de sus subdominios). Si el que envía la solicitud no coincide con el dominio propio del sitio, el RewriteRule final deniega la solicitud con una respuesta 403 Forbidden ([F]). En práctica, con esto nos aseguramos de que cualquiera que intente iniciar sesión lo hará si ha visitado primero el mismo dominio (emulando a un humano; los bots envían solicitudes directas sin visitar ninguna página previamente).
Advertencia: Debes reemplazar domain\.com con tu dominio real. Por ejemplo, si tu sitio es blog.accelerawp.com, debes cambiar la penúltima línea por:RewriteCond %{HTTP_REFERER} !^https?://([^/]+\.)?blog\.accelerawp\.com [NC]
¿Aún quieres usar un plugin de seguridad? Bueno…
Reitero que no necesitas un plugin de seguridad, pero si aún así quieres utilizar uno, echa un vistazo a mi artículo donde comparo qué opción tiene el menor impacto en tu sitio web en términos de rendimiento.
¿Y qué pasa con las cabeceras de seguridad?
Las cabeceras de seguridad, como Strict-Transport-Security o Content-Security-Policy, refuerzan la protección del navegador, por lo que sería más apropiado hablar de ellas en un artículo aparte. Este artículo se centra principalmente en los fundamentos de WordPress y del servidor. No tener estas cabeceras de seguridad no significa necesariamente que el sitio sea vulnerable; simplemente indica que esas cabeceras HTTP específicas no están configuradas actualmente.
¿Alguna otra sugerencia?
Comparte cualquier otra sugerencia en los comentarios, siempre y cuando no implique la instalación de plugins de seguridad 😉
Si ves un enlace de afiliado, te garantizo que es de un producto o servicio que realmente vale la pena. A diferencia de otras webs, aquí no se promociona nada solo porque paga más.



