Cómo crear un plugin de seguridad que bloquee intentos de login

Contents

Introducción

En la actualidad, los ataques de fuerza bruta y los intentos masivos de acceso no autorizado son amenazas constantes para las aplicaciones web, especialmente aquellas basadas en WordPress. Implementar un plugin de seguridad que detecte y bloquee ataques de login puede proteger tu sitio y tus usuarios. En este artículo se describe de forma detallada cómo diseñar, desarrollar e instalar un plugin de seguridad que limite intentos de acceso, almacene registros y notifique al administrador.

1. Objetivos y requisitos

  • Bloquear direcciones IP o nombres de usuario tras un número de intentos fallidos.
  • Registrar cada intento fallido con fecha, hora e IP.
  • Enviar alerts por correo al administrador.
  • Ofrecer una interfaz de configuración sencilla.

Requisitos previos:

  • Conocimientos básicos de PHP y WordPress Hooks.
  • Un entorno de desarrollo local o de staging.
  • Acceso FTP o gestor de archivos al servidor donde alojas WordPress.

2. Arquitectura del plugin

La siguiente tabla resume los componentes principales:

Componente Responsabilidad
Archivo principal (plugin) Declaración del plugin, hooks de inicialización.
Manejador de intentos Detecta intentos fallidos y lleva el conteo.
Bloqueador Impide accesos tras superar el límite.
Registro y notificaciones Guarda logs y envía emails al administrador.

3. Estructura de archivos

Recomendación de árbol de archivos:

  • login-blocker.php – Archivo principal.
  • includes/
    • handler.php – Lógica de conteo de intentos.
    • blocker.php – Funciones de bloqueo.
    • notifier.php – Envía correos y registra logs.
  • admin/
    • settings.php – Página de configuración en el panel.

4. Declaración del plugin

ltphp
/
Plugin Name: Login Blocker Security
Plugin URI: https://developer.wordpress.org/plugins/intro/
Description: Bloquea intentos de login después de un número de intentos fallidos y notifica al administrador.
Version: 1.0.0
Author: Tu Nombre
Author URI: https://example.com/
License: GPL2
/
defined(ABSPATH) exit

// Inclusión de archivos
require_once plugin_dir_path(__FILE__) . includes/handler.php
require_once plugin_dir_path(__FILE__) . includes/blocker.php
require_once plugin_dir_path(__FILE__) . includes/notifier.php

// Inicialización
add_action(init, lbs_init_plugin)
function lbs_init_plugin() {
LBS_Handler::setup()
LBS_Blocker::setup()
LBS_Notifier::setup()
}

5. Manejador de intentos fallidos

En includes/handler.php creamos la clase que captura login fallidos:

class LBS_Handler {
const OPTION_KEY = lbs_failed_logins

public static function setup() {
add_action(wp_login_failed, [__CLASS__, on_login_failed], 10, 1)
}

public static function on_login_failed(username) {
ip = _SERVER[REMOTE_ADDR]
attempts = get_transient(self::OPTION_KEY . _{ip}) : 0
attempts
set_transient(self::OPTION_KEY . _{ip}, attempts, HOUR_IN_SECONDS)
if (attempts >= 5) {
LBS_Blocker::block_ip(ip)
LBS_Notifier::notify_admin(ip, username, attempts)
}
}
}

Explicación:

  • Usamos transients para almacenar intentos por IP.
  • Tras 5 intentos, invocamos bloqueo y notificación.

6. Bloqueo de IP

En includes/blocker.php definimos cómo se impide el acceso:

class LBS_Blocker {
const BLOCK_KEY = lbs_blocked_ips

public static function setup() {
add_action(init, [__CLASS__, enforce_block])
}

public static function block_ip(ip) {
blocked = get_option(self::BLOCK_KEY, [])
if (!in_array(ip, blocked, true)) {
blocked[] = ip
update_option(self::BLOCK_KEY, blocked)
}
}

public static function enforce_block() {
ip = _SERVER[REMOTE_ADDR]
blocked = get_option(self::BLOCK_KEY, [])
if (in_array(ip, blocked, true)) {
wp_die(Acceso denegado. Tu IP ha sido bloqueada por múltiples intentos fallidos., Bloqueo de seguridad, [response =gt 403])
}
}
}

Este método enforce_block se ejecuta en cada carga y detiene el acceso si la IP está en la lista negra.

7. Registro y notificaciones

En includes/notifier.php se envía un correo y se guarda un log:

class LBS_Notifier {
public static function setup() {
// Posible hook adicional para administración
}

public static function notify_admin(ip, username, attempts) {
admin_email = get_option(admin_email)
subject = Alerta de bloqueo de login
message = Se han detectado {attempts} intentos de login fallidos.nIP: {ip}nUsuario: {username}
wp_mail(admin_email, subject, message)

error_log([LBS] IP bloqueada: {ip}, usuario: {username}, intentos: {attempts})
}
}

Recomendación: revisar wp_mail() y configurar SMTP seguro.

8. Panel de configuración

Para ofrecer opciones (umbral, duración de bloqueo), se puede añadir una página en el dashboard usando add_options_page y campos con settings_api. No entraremos en detalles aquí, pero recomendamos:

  • Registrar opciones con register_setting.
  • Gestionar formularios con settings_fields, do_settings_sections y submit_button.

9. Pruebas y despliegue

  1. Activar el plugin en un entorno de pruebas.
  2. Simular varios intentos de login fallido desde la misma IP.
  3. Verificar que se bloquea la IP y que el mensaje de error es claro.
  4. Comprobar que las notificaciones llegan al admin_email.
  5. Revisar logs de errores para asegurar que no hay warnings.

10. Buenas prácticas y mejoras

  • Implementar whitelist de IPs confiables.
  • Utilizar rate limiting en servidor (OWASP Top Ten recomienda monitorear el flujo de requests).
  • Almacenar logs en base de datos propia o servicio externo para análisis profundo.
  • Agregar reCAPTCHA u otros mecanismos de validación.
  • Permitir desbloqueo automático tras período definido.

Conclusión

Crear un plugin de seguridad que bloquea intentos de login ofrece una capa adicional contra ataques de fuerza bruta. Siguiendo esta guía, dispondrás de un sistema modular, fácil de mantener y extensible. Para profundizar, revisa la documentación oficial de WordPress en WordPress Plugin Developer Handbook y las recomendaciones de OWASP.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

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