🛡️ Cómo proteger una API contra ataques: rate limiting, headers y seguridad real en PHP
Introducción
Crear una API funcional es fácil.
Crear una API segura… es otra historia.
En cuanto tu API está expuesta a internet, automáticamente empieza a recibir:
- bots
- intentos de fuerza bruta
- scraping agresivo
- ataques automatizados
- requests masivos
- intentos de acceso indebido
👉 aunque tu proyecto sea pequeño
Y aquí está la realidad:
Si no proteges tu API, no es cuestión de “si” te atacan…
es cuestión de cuándo y cómo.
En este tutorial vas a aprender:
- cómo proteger tu API desde backend
- qué es rate limiting y cómo implementarlo
- headers de seguridad importantes
- validación de requests
- protección básica contra abusos
- patrones reales usados en producción
Todo aplicado a PHP + APIs REST.
⚠️ Qué tipos de ataques recibe una API
Antes de proteger, hay que entender el problema.
Los más comunes:
🔹 Fuerza bruta
Intentos masivos de login.
🔹 Spam de requests
Miles de peticiones por segundo.
🔹 Scraping agresivo
Bots consumiendo tu API sin control.
🔹 Enumeración
Probar IDs para descubrir datos.
🔹 Tokens robados
Uso indebido de JWT.
👉 Todo esto es normal en producción.
🧱 Capa 1: Validación básica (obligatoria)
Antes de todo:
👉 no confíes en el cliente
Siempre valida:
if (!isset($data['email'])) {
http_response_code(400);
exit;
}
🔐 Usa prepared statements SIEMPRE
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE email = ?");
$stmt->execute([$email]);
👉 evita SQL injection
🚦 Capa 2: Rate limiting (lo más importante)
🧠 Qué es rate limiting
Limitar cuántas peticiones puede hacer un usuario/IP.
Ejemplo:
👉 máximo 100 requests por minuto
🔥 Por qué es clave
Sin rate limiting:
- te pueden tumbar el servidor
- pueden probar miles de contraseñas
- pueden abusar de tu API
🧩 Implementación simple en PHP
Estrategia: usar IP + tiempo
Ejemplo básico con archivo (simple)
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$file = sys_get_temp_dir() . "/rate_" . md5($ip);
$limit = 100;
$window = 60; // segundos
$data = [
"count" => 0,
"time" => time()
];
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
}
if (time() - $data['time'] > $window) {
$data = ["count" => 0, "time" => time()];
}
$data['count']++;
if ($data['count'] > $limit) {
http_response_code(429);
exit(json_encode(["error" => "Too many requests"]));
}
file_put_contents($file, json_encode($data));
🧠 Mejor opción (recomendada): base de datos o Redis
Para producción:
- Redis (ideal)
- MySQL (aceptable)
Ejemplo con MySQL
Tabla:
CREATE TABLE rate_limit ( ip VARCHAR(45), requests INT, last_request TIMESTAMP );
👉 luego controlas por IP + tiempo
🔐 Capa 3: Headers de seguridad
Esto es MUY importante y casi nadie lo implementa.
Añade estos headers en tu API
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: DENY");
header("X-XSS-Protection: 1; mode=block");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
🔒 Content Security Policy (opcional)
header("Content-Security-Policy: default-src 'self'");
👉 ayuda contra ataques XSS
🔑 Capa 4: Protección de JWT
JWT mal usado = problema.
Buenas prácticas
- tokens cortos (15–30 min)
- usar refresh tokens
- validar expiración
- no confiar solo en token
- usar HTTPS
Validación obligatoria
JWT::decode($token, new Key($key, 'HS256'));
🚫 Capa 5: bloquear IPs sospechosas
Puedes combinar con:
- fail2ban (nivel servidor)
- logs + blacklist
Ejemplo simple:
$blacklist = ['192.168.1.10'];
if (in_array($_SERVER['REMOTE_ADDR'], $blacklist)) {
http_response_code(403);
exit;
}
🔍 Capa 6: validar headers y origen
Puedes verificar:
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if ($origin !== 'https://tusitio.com') {
http_response_code(403);
exit;
}
👉 útil en APIs privadas
🔐 Capa 7: proteger login (muy importante)
Ejemplo:
- máximo 5 intentos por minuto
- bloquear temporalmente
Ejemplo simple:
if ($loginAttempts > 5) {
http_response_code(429);
exit("Demasiados intentos");
}
📦 Capa 8: limitar tamaño de requests
Evita payloads enormes:
if ($_SERVER['CONTENT_LENGTH'] > 100000) {
http_response_code(413);
exit;
}
🧠 Capa 9: logging (nivel pro)
Guarda:
- IP
- endpoint
- errores
- intentos fallidos
Ejemplo:
file_put_contents("logs.txt", $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND);
👉 mejor en BD o sistema de logs
🚨 Capa 10: respuestas controladas
No hagas esto:
echo $e->getMessage();
👉 filtra info sensible
🧪 Ejemplo real de protección combinada
Una API protegida debe tener:
- JWT
- rate limit
- validación
- headers
- logs
⚠️ Errores comunes
❌ no usar rate limiting
❌ confiar en frontend
❌ tokens largos
❌ sin HTTPS
❌ sin logs
🔐 Buenas prácticas
- defensa en capas
- validar todo
- limitar todo
- loggear eventos
- pensar como atacante
🧠 Mentalidad clave
👉 seguridad no es una cosa
👉 es un sistema completo
🧩 Conclusión:
Una API segura no depende de una sola técnica.
Depende de:
- capas de protección
- buenas prácticas
- control
- monitoreo
Si aplicas esto:
👉 tu API pasa de “proyecto” a “producto serio”
🔗 Siguiente lectura recomendada:
- Sistema de login completo con JWT + PHP + MySQL (paso a paso)
- Refresh tokens en PHP explicados fácil
- Cómo proteger una API contra ataques: rate limiting, headers y seguridad real en PHP
- linux seguridad