Un ataque DDoS a un sitio WordPress es algo que se ve cada vez más común. Este tipo de ataques, es de saturacion. cientos o miles de visitas de distintas IPs de manera distribuida, hacen que tu sitio cargue, genere procesos y consultas mysql, muchas veces por segundo, evitando que haya recursos para los visitantes reales.
Si tu sitio WordPress atrae un ataque DDoS, la mejor forma de protegerlo es con CloudFlare.
Sin embargo, si no quieres utilizar CloudFlare, o necesitas protegerlo ya, existe otra manera, de generar un tipo de captcha manualmente. Esto es especialmente util cuando el ataque es únicamente contra el index.php
Proteger index.php de WordPress ante ataques DDoS
- Renombra el index.php de tu sitio wordpress por wp-index.php
- Crea un segundo index.php con el siguiente codigo:
<?php
// Inicia la sesión para recordar al usuario verificado y los intentos.
session_start();
// --- CONFIGURACIÓN ---
// Añade tu IP aquí para saltarte siempre la verificación.
// Puedes encontrar tu IP buscando en Google "what is my ip".
$admin_ips = ['192.168.1.100', 'TU_OTRA_IP_SI_TIENES'];
// Ruta al logo de tu sitio web. Déjalo en blanco ('') si no quieres usar uno.
$logo_path = '';
// Nombre de tu sitio web para el título de la página.
$site_name = 'NombreDeTuSitioWeb';
// --------------------
// --- LISTA BLANCA (WHITELIST) ---
// User agents de bots conocidos que queremos dejar pasar para no afectar el SEO.
$whitelisted_user_agents = ['Googlebot', 'Bingbot', 'Slurp', 'DuckDuckBot', 'Baiduspider'];
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
foreach ($whitelisted_user_agents as $bot) {
if (stripos($user_agent, $bot) !== false) {
$_SESSION['is_human'] = true; // Lo marcamos como "humano" para futuras visitas en la misma sesión.
require_once 'wp-index.php';
exit();
}
}
// Revisa si la IP del visitante está en la lista de administradores.
if (in_array($_SERVER['REMOTE_ADDR'], $admin_ips)) {
require_once 'wp-index.php';
exit();
}
// ---------------------------------
// Si el usuario ya está verificado en la sesión, carga WordPress.
if (isset($_SESSION['is_human']) && $_SESSION['is_human'] === true) {
require_once 'wp-index.php';
exit();
}
// --- LÓGICA DEL CAPTCHA Y SEGURIDAD ---
$error = '';
// Inicializa el contador de intentos fallidos si no existe.
if (!isset($_SESSION['failed_attempts'])) {
$_SESSION['failed_attempts'] = 0;
}
// Si se ha superado el límite de intentos, muestra un mensaje y no proceses más.
if ($_SESSION['failed_attempts'] >= 3) {
http_response_code(429); // Too Many Requests
$error = 'Has superado el número de intentos permitidos. Por favor, inténtalo de nuevo más tarde.';
}
// Si el formulario fue enviado
elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 1. Verificación de Honeypot: si el campo oculto tiene algo, es un bot.
if (!empty($_POST['contact_email'])) {
http_response_code(403);
die('Acceso denegado.');
}
// 2. Verificación de tiempo: si se envió en menos de 2 segundos, es un bot.
$time_submitted = time();
if (isset($_SESSION['form_load_time']) && ($time_submitted - $_SESSION['form_load_time']) < 2) {
http_response_code(403);
die('Acceso denegado.');
}
// 3. Verificación de la respuesta del CAPTCHA.
if (isset($_POST['captcha_answer'], $_SESSION['captcha_sum'])) {
if ($_POST['captcha_answer'] == $_SESSION['captcha_sum']) {
// Respuesta correcta: marca al usuario como humano y resetea los intentos.
$_SESSION['is_human'] = true;
$_SESSION['failed_attempts'] = 0;
unset($_SESSION['captcha_sum'], $_SESSION['captcha_question'], $_SESSION['form_load_time']); // Limpia la sesión
header('Location: ' . $_SERVER['REQUEST_URI']);
exit();
} else {
// Respuesta incorrecta: incrementa el contador de fallos.
$_SESSION['failed_attempts']++;
$error = 'Respuesta incorrecta. Por favor, intenta de nuevo.';
}
}
}
// Genera una nueva pregunta si no existe una o si la página se recarga.
$num1 = rand(1, 9);
$num2 = rand(1, 9);
$_SESSION['captcha_question'] = "¿Cuánto es $num1 + $num2?";
$_SESSION['captcha_sum'] = $num1 + $num2;
// Guarda el tiempo en que el formulario fue cargado.
$_SESSION['form_load_time'] = time();
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verificación de seguridad | <?php echo htmlspecialchars($site_name); ?></title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #0073aa; /* Color primario (similar al de WordPress) */
--background-color: #f0f2f5;
--container-bg: #ffffff;
--text-color: #333;
--error-color: #d9534f;
}
body {
font-family: 'Roboto', sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: var(--background-color);
color: var(--text-color);
}
.container {
padding: 40px;
background-color: var(--container-bg);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
text-align: center;
max-width: 400px;
width: 90%;
}
.logo {
max-width: 150px;
margin-bottom: 20px;
}
h1 {
margin-top: 0;
font-size: 1.5em;
}
p {
margin-bottom: 20px;
}
form label {
font-weight: 700;
margin-bottom: 10px;
display: block;
}
/* Estilo para el campo trampa (Honeypot) - ¡No lo borres! */
.honeypot-field {
opacity: 0;
position: absolute;
top: 0;
left: 0;
height: 0;
width: 0;
z-index: -1;
}
input[type="text"] {
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
width: 80px; /* Ancho justo para la respuesta */
text-align: center;
font-size: 1.1em;
}
input[type="submit"] {
padding: 12px 25px;
background-color: var(--primary-color);
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1em;
font-weight: 700;
transition: background-color 0.3s;
}
input[type="submit"]:hover {
background-color: #005a87;
}
.error {
color: var(--error-color);
margin-top: 15px;
font-weight: 700;
}
</style>
</head>
<body>
<div class="container">
<?php if ($logo_path): ?>
<img src="<?php echo htmlspecialchars($logo_path); ?>" alt="Logo de <?php echo htmlspecialchars($site_name); ?>" class="logo">
<?php endif; ?>
<h1>Verificación de Seguridad</h1>
<?php if ($_SESSION['failed_attempts'] >= 3): ?>
<p class="error"><?php echo $error; ?></p>
<?php else: ?>
<p>Para proteger el sitio contra bots, por favor, responde la siguiente pregunta.</p>
<form method="post" action="">
<label for="captcha_answer"><?php echo $_SESSION['captcha_question']; ?></label>
<div class="honeypot-field">
<label for="contact_email">Email</label>
<input type="email" name="contact_email" id="contact_email" tabindex="-1" autocomplete="off">
</div>
<input type="text" name="captcha_answer" id="captcha_answer" required autofocus inputmode="numeric" pattern="[0-9]*">
<br><br>
<input type="submit" value="Verificar Acceso">
</form>
<?php if ($error): ?>
<p class="error"><?php echo $error; ?></p>
<?php endif; ?>
<?php endif; ?>
</div>
</body>
</html>
- Listo. Esto hará que la primera vez de un visitante, en lugar de cargar todos tus procesos, consultas mysql, plugins, widgets, etc, les aparezca un problema matematico simple. es decir un captcha 🙂