Skip to content
IRC-CodingIRC-Coding
Seguridad REST APIAutenticaciónAutorizaciónOAuth 2.0JWTRBACCORSAPI Security

Seguridad REST API: Autenticación y Autorización

Seguridad REST API: Autenticación vs autorización, OAuth 2.0, JWT, RBAC, ABAC, CORS, CSRF y mejores prácticas.

S

schutzgeist

13 min read
Seguridad REST API: Autenticación y Autorización

Seguridad en REST APIs: Autenticación, Autorización y Medidas de Protección

La seguridad en REST APIs garantiza que solo clientes autorizados accedan a recursos permitidos. Quien construye APIs debe entender autenticación y autorización: son el fundamento de cualquier interfaz segura.

¿Qué es la seguridad en REST APIs?

La seguridad en REST APIs comprende todas las medidas que protegen una API RESTful contra acceso no autorizado, manipulación y ataques. Se sustenta en dos pilares centrales:

Autenticación responde: ¿Quién eres? El cliente prueba su identidad mediante tokens, claves API, certificados o cookies de sesión.

Autorización responde: ¿Puedes hacerlo? Tras autenticar al cliente, se verifica si tiene permisos para ejecutar la acción solicitada.

Esta separación es esencial. Un usuario autenticado no está autorizado automáticamente a hacer cualquier cosa. Un usuario puede leer sus propios datos, pero no los ajenos. Un administrador tiene más permisos que un editor. Este principio se implementa mediante modelos como RBAC (Role-Based Access Control) o ABAC (Attribute-Based Access Control).

¿Quién utiliza seguridad en REST APIs?

  • Desarrolladores backend implementan middleware de autenticación y lógica de autorización
  • Diseñadores de APIs definen qué protección necesita cada endpoint
  • Ingenieros DevOps configuran TLS, rate limiting y API gateways
  • Ingenieros de seguridad auditan APIs en busca de vulnerabilidades
  • Desarrolladores frontend deben enviar tokens de autenticación correctamente

¿Por qué es importante este tema en informática y en exámenes?

El Top 10 de OWASP enumera Broken Access Control en el puesto 1 y Cryptographic Failures en el 2, ambos afectan directamente la seguridad de APIs. En exámenes de la Cámara de Industria y Comercio, en estudios de informática y en certificaciones se preguntan regularmente las diferencias entre autenticación y autorización, OAuth 2.0, JWT y headers de seguridad.

Conceptos fundamentales en detalle

Métodos de autenticación para REST APIs

API-Key

El cliente envía una clave estática en el header X-API-Key. El servidor la compara con su base de datos.

Ventajas: simple, adecuado para comunicación servidor a servidor. Desventajas: sin expiración, sin permisos granulares, acceso completo en caso de compromiso.

Autenticación basada en sesiones

El cliente envía credenciales (usuario/contraseña). El servidor crea una sesión, la almacena en su lado y devuelve una ID de sesión en una cookie. En cada nueva petición, el navegador envía la cookie automáticamente.

Ventajas: control en el servidor, la sesión puede invalidarse en cualquier momento. Desventajas: escalabilidad limitada con múltiples instancias (requiere session store compartido), riesgo de CSRF con cookies.

Autenticación basada en tokens (JWT)

El cliente envía credenciales. El servidor crea un JSON Web Token (JWT) que contiene claims como ID de usuario, roles y tiempo de expiración. El token está firmado criptográficamente. El cliente lo envía en cada petición en el header Authorization: Bearer <token>.

Ventajas: sin estado (stateless), escalable, no requiere session store. Desventajas: el token no puede revocarse fácilmente antes de expirar (excepto con listas de revocación o blacklists).

OAuth 2.0

OAuth 2.0 es un framework para autorización delegada. Un cliente recibe un access token de un servidor de autorización después de que el resource owner (el usuario) da su consentimiento. El token permite acceder a recursos específicos durante un tiempo limitado.

Flujos principales:

  • Authorization Code Flow: estándar para aplicaciones web con backend servidor
  • PKCE Flow: para SPAs y aplicaciones móviles sin client secret
  • Client Credentials Flow: para comunicación servidor a servidor sin participación del usuario

Modelos de autorización

RBAC (Role-Based Access Control)

Los usuarios se asignan a roles. Los roles tienen permisos. La verificación es: ¿Tiene el usuario el rol que permite esta acción?

Ejemplo: el rol admin puede todo, el rol editor puede leer y escribir, el rol viewer solo puede leer.

Ventajas: fácil de entender, adecuado para sistemas con alcance manejable. Desventajas: explosión de roles con permisos muy granulares.

ABAC (Attribute-Based Access Control)

El control de acceso se basa en atributos del sujeto, recurso, acción y entorno. La verificación es: ¿Cumple la combinación de todos los atributos la política?

Ejemplo: un médico puede leer datos de pacientes solo durante sus horas de trabajo y solo para pacientes de su departamento.

Ventajas: muy granular, basado en políticas. Desventajas: más complejo de implementar y mantener.

Autorización basada en propiedad de recurso

El usuario solo puede acceder a recursos que le pertenecen. Una orden solo puede verla su propietario. La verificación requiere una consulta a la base de datos: ¿Pertenece este recurso al usuario autenticado?

Medidas de seguridad adicionales

TLS (Transport Layer Security)

Toda API debe ejecutarse sobre HTTPS. Sin TLS, los tokens y credenciales pueden ser interceptados. TLS cifra el transporte y garantiza la integridad de los datos transmitidos.

CORS (Cross-Origin Resource Sharing)

CORS determina qué orígenes externos pueden acceder a la API. El servidor envía el header Access-Control-Allow-Origin. Sin configuración CORS correcta, los clientes basados en navegador pueden bloquearse, o peor aún, orígenes arbitrarios obtienen acceso.

Protección CSRF

Con autenticación basada en cookies existe riesgo de CSRF. Un atacante puede lograr que el navegador envíe una cookie automáticamente. Medidas de protección: tokens CSRF, atributo de cookie SameSite, header Authorization en lugar de cookies.

Rate Limiting

Limita el número de peticiones por cliente en un período de tiempo. Protege contra ataques de fuerza bruta, credential stuffing y DoS. Típicamente: 100 peticiones por minuto por token.

Validación de entrada

Toda entrada debe validarse. SQL injection, XSS y command injection surgen de validación faltante o insuficiente. Utiliza prepared statements, validación de esquemas y whitelisting.

¿Por qué es importante la seguridad en REST APIs en la práctica?

Una API insegura es una ventana abierta a tus datos. Escenarios realistas:

  • Token comprometido: un access token se almacena en logs o se codifica en el código cliente. Un atacante lo encuentra y accede a todos los datos del usuario afectado.
  • Broken Object Level Authorization (BOLA): la API solo verifica si el usuario está autenticado, pero no si tiene acceso al recurso solicitado. Un usuario llama a /api/orders/42 y ve la orden de otro usuario.
  • Mass Assignment: el cliente envía un campo como {"role":"admin"} al actualizar el perfil. El servidor lo adopta sin verificación. El usuario se hace administrador a sí mismo.
  • Sin rate limiting: un atacante prueba 10.000 contraseñas por segundo. Sin rate limiting, rompe la contraseña en minutos.

Ejemplo práctico: API de Express.js con JWT y RBAC

Este ejemplo muestra una API REST completa con autenticación (JWT) y autorización (RBAC). Se eligió porque reúne los conceptos más importantes en código compacto: creación de tokens, verificación de autenticación basada en middleware, control de acceso basado en roles y verificación de propiedad.

// auth-middleware.js
// Middleware: verifica JWT del header Authorization
function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({
      error: 'UNAUTHORIZED',
      message: 'Se requiere autenticación. Envía un token Bearer.'
    });
  }

  const token = authHeader.split(' ')[1];
  try {
    // jwt.verify lanza una excepción con token inválido o expirado
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload; // { userId: 42, role: 'editor', exp: 1234567890 }
    next();
  } catch (err) {
    return res.status(401).json({
      error: 'INVALID_TOKEN',
      message: 'El token es inválido o ha expirado.'
    });
  }
}

// Middleware: verifica si el usuario tiene uno de los roles requeridos
function authorize(...roles) {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({
        error: 'UNAUTHORIZED',
        message: 'Se requiere autenticación.'
      });
    }
    if (!roles.includes(req.user.role)) {
      return res.status(403).json({
        error: 'FORBIDDEN',
        message: `Rol requerido: ${roles.join(' o ')}.`
      });
    }
    next();
  };
}

// Middleware: verifica si el usuario es propietario del recurso
function checkOwnership(getResourceId) {
  return async (req, res, next) => {
    const resourceId = getResourceId(req);
    const resource = await db.orders.findById(resourceId);
    if (!resource) {
      return res.status(404).json({
        error: 'NOT_FOUND',
        message: 'Recurso no encontrado.'
      });
    }
    // Los administradores pueden todo, otros solo sus propios recursos
    if (req.user.role !== 'admin' && resource.userId !== req.user.userId) {
      return res.status(403).json({
        error: 'FORBIDDEN',
        message: 'Solo puedes acceder a tus propios recursos.'
      });
    }
    req.resource = resource;
    next();
  };
}
// routes.js
// Aplicación del middleware a varios endpoints

// Login: autenticación -> emisión de JWT
app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await db.users.findByEmail(email);
  if (!user || !await bcrypt.compare(password, user.passwordHash)) {
    return res.status(401).json({
      error: 'INVALID_CREDENTIALS',
      message: 'Email o contraseña incorrectos.'
    });
  }
  const token = jwt.sign(
    { userId: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: '15m' }
  );
  res.json({ token });
});

// Rutas protegidas: authenticate para todos, authorize para roles específicos
app.get('/api/orders', authenticate, async (req, res) => {
  // Usuarios normales ven solo sus órdenes
  if (req.user.role === 'admin') {
    const orders = await db.orders.findAll();
    res.json(orders);
  } else {
    const orders = await db.orders.findByUserId(req.user.userId);
    res.json(orders);
  }
});

app.get('/api/orders/:id', authenticate, checkOwnership(req => req.params.id), (req, res) => {
  res.json(req.resource);
});

app.post('/api/orders', authenticate, async (req, res) => {
  const order = await db.orders.create({
    ...req.body,
    userId: req.user.userId
  });
  res.status(201).json(order);
});

app.delete('/api/orders/:id', authenticate, authorize('admin'), checkOwnership(req => req.params.id), async (req, res) => {
  await db.orders.delete(req.params.id);
  res.status(204).send();
});

Información detallada

Tiempo de vida de tokens y Refresh Tokens

Los Access Tokens deben ser efímeros (15 minutos). Los Refresh Tokens tienen una vida más larga (días a semanas) y sirven únicamente para obtener nuevos Access Tokens. Si se compromete un Access Token, solo será útil durante poco tiempo. Si se compromete un Refresh Token, puede revocarse en el servidor.

Estructura JWT

Un JWT consta de tres partes codificadas en Base64: Header, Payload y Signature. El Header contiene el algoritmo y el tipo. El Payload contiene Claims como sub (Subject), exp (Expiration), iat (Issued At), role, userId. La Signature se calcula con el Secret o Private Key.

Importante: el Payload solo está codificado en Base64, no cifrado. Nunca almacenes datos sensibles en el JWT. La seguridad proviene de la firma, que garantiza que el token no ha sido alterado.

Headers de seguridad para REST APIs

HeaderPropósito
Strict-Transport-SecurityFuerza HTTPS
X-Content-Type-Options: nosniffPreviene MIME-Sniffing
X-Frame-Options: DENYPreviene Clickjacking
Cache-Control: no-storeEvita cachear respuestas sensibles
Access-Control-Allow-OriginConfiguración CORS

Vulnerabilidades comunes (OWASP API Security Top 10)

  1. BOLA (Broken Object Level Authorization): Sin verificación de propiedad
  2. Broken Authentication: Creación débil de tokens, sin Rate Limits
  3. Excessive Data Exposure: La API devuelve más campos de los necesarios
  4. Lack of Resources & Rate Limiting: Sin límite en el número de solicitudes
  5. Broken Function Level Authorization: Sin verificación de rol por endpoint
  6. Mass Assignment: Aceptación sin filtros de campos de entrada
  7. Security Misconfiguration: Secrets por defecto, modo debug, CORS abierto

Resumen de mejores prácticas

  • Usa HTTPS siempre y exclusivamente
  • Access Tokens efímeros (15 min), Refresh Tokens revocables
  • RBAC para derechos generales, ABAC para políticas granulares
  • Verificación de propiedad en cada endpoint que afecte recursos específicos
  • Rate Limiting en nivel IP y nivel token
  • Validación de entrada con esquema y whitelist
  • Ningún dato sensible en el Payload del JWT
  • Establece headers de seguridad
  • Mensajes de error sin detalles internos
  • Auditorías de seguridad y pruebas de penetración regulares

FAQ: Seguridad REST API

1. ¿Cuál es la diferencia entre autenticación y autorización?

La autenticación verifica la identidad de un cliente (¿Quién eres?), mientras que la autorización comprueba si el cliente identificado tiene permiso para realizar una acción específica (¿Puedes hacerlo?). La autenticación ocurre típicamente mediante login con credenciales, la autorización mediante verificación de roles o atributos.

2. ¿Qué es RBAC?

RBAC (Role-Based Access Control) es un modelo de autorización donde se asignan roles a usuarios y permisos a roles. El control de acceso verifica si el usuario tiene el rol requerido. Es fácil de entender, pero puede llevar a explosión de roles cuando los permisos son muy granulares.

3. ¿Qué es ABAC?

ABAC (Attribute-Based Access Control) es un modelo de autorización donde el control de acceso se basa en atributos del sujeto, recurso, acción y contexto. Las políticas definen qué combinaciones de atributos permiten qué acceso. ABAC es más granular que RBAC, pero más complejo de implementar.

4. ¿Qué es Broken Object Level Authorization (BOLA)?

BOLA es la vulnerabilidad más común en APIs según OWASP. La API verifica que el usuario esté autenticado, pero no si tiene acceso al recurso solicitado. Un usuario puede acceder a datos ajenos simplemente cambiando el ID en la URL. Protección: verificar propiedad en cada endpoint.

5. ¿Por qué deben ser efímeros los Access Tokens?

Los Access Tokens deben ser efímeros (por ejemplo, 15 minutos) porque si se comprometen, solo son útiles brevemente. Una vida más larga significa mayor riesgo. Para sesiones más largas se usan Refresh Tokens, que pueden revocarse en el servidor.

6. ¿Cuál es la diferencia entre JWT y Session-Cookies?

JWT es sin estado (stateless): el servidor no almacena sesiones, toda la información está en el token. Los Session-Cookies requieren un almacén de sesiones en el servidor. JWT escala mejor, pero es más difícil de revocar. Las sesiones son más fáciles de invalidar, pero necesitan estado compartido entre múltiples servidores.

7. ¿Qué es Mass Assignment y cómo prevenirlo?

Mass Assignment ocurre cuando el servidor acepta todos los campos de entrada sin validar. Un cliente podría enviar un campo como role: admin y otorgarse derechos de administrador. Protección: selección explícita de campos (whitelist), DTOs que contengan solo los campos permitidos y validación de entrada.

8. ¿Por qué es importante CORS para la seguridad de API?

CORS (Cross-Origin Resource Sharing) controla qué orígenes externos pueden acceder a la API desde el navegador. Sin configuración CORS, se pueden bloquear clientes legítimos o, si es demasiado abierta, permitir que cualquier sitio web acceda a la API. La configuración correcta es una lista de orígenes específicos permitidos.

9. ¿Qué es CSRF y cómo afecta a REST APIs?

CSRF (Cross-Site Request Forgery) ocurre cuando un atacante induce al navegador de un usuario a enviar una solicitud a la API, con la cookie de sesión enviada automáticamente. Con autenticación basada en tokens en el header Authorization, CSRF no es un riesgo porque el navegador no envía el header automáticamente. Con auth basada en cookies, deben usarse CSRF-Tokens y atributos SameSite.

10. ¿Los Payloads de JWT están cifrados?

No, el Payload del JWT solo está codificado en Base64, no cifrado. Cualquiera que intercepte el token puede leer el Payload. La seguridad proviene de la firma, que previene manipulación. Para contenido confidencial, debe usarse JWE (JSON Web Encryption).

11. ¿Qué es el flujo PKCE en OAuth 2.0?

PKCE (Proof Key for Code Exchange) extiende el Authorization Code Flow para SPAs y aplicaciones móviles que no pueden almacenar Client Secret de forma segura. El cliente genera un Code Verifier y envía su hash (Code Challenge) al Authorization Server. Al intercambiar el código por un token, el cliente debe enviar el Verifier original, lo que hace inútil la intercepción del código de autorización.

12. ¿Cómo funciona Rate Limiting en APIs?

Rate Limiting limita el número de solicitudes por cliente en un período. Los métodos típicos son Fixed Window (por ejemplo, 100 requests por minuto), Sliding Window y Token Bucket. El límite puede aplicarse por dirección IP, API Key o token. Al exceder, el servidor responde con 429 Too Many Requests e incluye un header Retry-After.

13. ¿Qué códigos HTTP son relevantes para errores de autenticación?

401 Unauthorized significa que falta autenticación o es inválida. 403 Forbidden significa que el cliente está autenticado pero no tiene permiso para la acción solicitada. 429 Too Many Requests indica que se han enviado demasiadas solicitudes.

14. ¿Qué es el Principle of Least Privilege?

El Principle of Least Privilege establece que cada cliente y usuario recibe solo los permisos mínimos necesarios para su tarea. Un cliente de lectura no obtiene derecho de escritura. Un editor no obtiene derechos de administrador. Esto reduce la superficie de ataque si se compromete una cuenta.

15. ¿Cómo se revoca un JWT antes de su expiración?

Dado que JWT es sin estado, no puede revocarse fácilmente. Las soluciones son: mantener una lista de revocación (blacklist) en el servidor y verificarla en cada solicitud, o usar tokens con vida corta junto con Refresh Tokens revocables. En logout, se invalida el Refresh Token asociado para que no se emitan nuevos Access Tokens.

Continuando en la ruta de aprendizaje de API

El siguiente artículo en la ruta de aprendizaje de API cubre API Security Best Practices: APIs schützen, absichern und betreiben — las medidas de seguridad más importantes para operar APIs siguiendo OWASP y mejores prácticas.

Referencias y recursos adicionales

  1. https://owasp.org/API-Security/editions/2023/en/0x11-t10/
  2. https://datatracker.ietf.org/doc/html/rfc6749 (OAuth 2.0)
  3. https://datatracker.ietf.org/doc/html/rfc7519 (JWT)
  4. https://owasp.org/www-project-top-ten/
  5. https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html

Lecturas recomendadas para desarrollo de APIs

Keine Bücher für Kategorie "api-development" gefunden.

Volver al blog
Share:

Nächster Artikel in Desarrollo de API

Weiterlesen
REST API: HTTP, Statuscodes y HATEOAS

Entradas relacionadas