🛡️ 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: