Ir al contenido principal
Laravel, shipping fast.
Capitulo 4 · El pipeline de peticiones

Lista de comprobacion de seguridad

Julian Beaujardin

Antes de publicar:

  • [X] Los tokens Bearer son sin estado y se validan contra la base de datos
  • [X] Los tokens se cachean para minimizar consultas
  • [X] La expiración se impone (los tokens caducados se rechazan de inmediato)
  • [X] La revocación es posible (borrar o expirar el token)
  • [X] La validación de dominio restringe el uso a orígenes aprobados
  • [X] El límite de frecuencia previene el abuso a nivel de token, no de IP
  • [X] Las cabeceras de límite informan al cliente de su cuota
  • [X] El registro es asíncrono (no bloquea las respuestas)
  • [X] Los tokens nunca se registran en claro (sólo hasheados)
  • [X] La configuración es dinámica por token (sin secretos a fuego)
  • [X] Todas las rutas protegidas usan la misma pila de middleware
  • [X] Los FormRequests validan toda la entrada
  • [X] Todos los endpoints devuelven una estructura de error consistente
  • [X] La inyección SQL se previene (Eloquent, consultas parametrizadas)
  • [X] Se fuerza HTTPS en producción

La seguridad no es una funcionalidad. No es un sprint. Es una disciplina. Sigue estos patrones, pruébalos, y tu API estará protegida por su arquitectura y no por buenas intenciones.

Escenarios de amenaza reales

Tu arquitectura previene amenazas concretas:

Robo de token. Un atacante roba un token Bearer. Con validación de dominio, sólo funciona desde el dominio permitido. Desde attacker.com recibe un 401.

Ataques de denegación de servicio. Un cliente malicioso envía diez mil peticiones por minuto. El límite por token lo detiene a las sesenta. El servidor sigue sano.

Enumeración de tokens. Un atacante prueba tokens al azar. El hashing previene ataques de tiempo.

Reutilización de tokens expirados. Un token revocado hace una hora se rechaza de inmediato por la comprobación de expiración.

Divulgación de información. Mal: «Token abc123 no encontrado». Bien: un 401 Unauthorized genérico. No expongas la implementación.

Registro de credenciales. Nunca registres Authorization: Bearer secreto en claro. Registra un hash y correlaciona sin exponer.

Probar la autenticacion

Probar la autenticación es directo porque los tokens Bearer son sólo filas en una base de datos:

// Happy path: valid token
test('valid bearer token is accepted', function () {
    $bearer = Bearer::factory()->create();

    $response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
        ->get('/api/licenses');

    expect($response->status())->toBe(200);
});
// Expired token
test('expired bearer token is rejected', function () {
    $bearer = Bearer::factory()
        ->expired()
        ->create();

    $response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
        ->get('/api/licenses');

    expect($response->status())->toBe(401);
});
// Domain restriction
test('bearer token is rejected if domain does not match', function () {
    $bearer = Bearer::factory()
        ->withDomains(['https://allowed-domain.com'])
        ->create();

    $response = $this->withHeader('Authorization', "Bearer {$bearer->token}")
        ->from('https://wrong-domain.com')
        ->get('/api/licenses');

    expect($response->status())->toBe(401);
});
// Rate limiting
test('rate limit is enforced after 60 requests per minute', function () {
    $bearer = Bearer::factory()->create();
    $headers = ['Authorization' => "Bearer {$bearer->token}"];

    // Make requests up to limit
    for ($i = 0; $i < 60; $i++) {
        $this->withHeaders($headers)->get('/api/licenses');
    }

    // Next request should be rate limited
    $response = $this->withHeaders($headers)->get('/api/licenses');
    expect($response->status())->toBe(429);
});

Creando estados en tu factory, probar distintos escenarios es trivial. Sin simular clientes HTTP, sin sustituir APIs externas. Sólo estados del modelo Bearer y aserciones.

Cuando NO usar estos patrones

Conoce tus restricciones:

Validación de dominio. Úsala cuando haya varios socios con credenciales distintas y el robo de tokens sea crítico. Sáltala en APIs internas con tokens de vida corta.

Límite por token. Úsalo cuando los clientes tengan necesidades distintas o cobres por uso. Sáltalo si todos los clientes son iguales.

Cacheo de tokens. Úsalo cuando los tokens se consulten con frecuencia y toleres retrasos en la revocación. Sáltalo si necesitas revocación instantánea.

Registro asíncrono. Úsalo en APIs con mucho tráfico donde la latencia del registro importe. Sáltalo si necesitas un rastro de auditoría síncrono.

Tokens Bearer. Úsalos para autenticación de servicio a servicio. Sáltalos para SPAs multiusuario (usa Sanctum).

La seguridad no es de talla única. Mide y ajusta.