Wiki/Fundamentos/Autenticación y Autorización
Principiante
18 min lectura

Autenticación y Autorización

Dos conceptos fundamentales de seguridad que a menudo se confunden pero tienen roles distintos

¿Qué son Autenticación y Autorización?

Autenticación (AuthN)

¿Quién eres? - Verificar la identidad del usuario.

Ejemplos: Login con usuario/contraseña, 2FA, biometría, OAuth

Autorización (AuthZ)

¿Qué puedes hacer? - Verificar los permisos del usuario.

Ejemplos: Roles, permisos, ACLs, RBAC, políticas de acceso

Importante

La autenticación siempre viene ANTES que la autorización. Primero verificamos quién eres, luego verificamos qué puedes hacer. No tiene sentido verificar permisos sin saber quién los solicita.

Autenticación en Profundidad

Factores de Autenticación

1. Algo que sabes (Knowledge)

  • • Contraseñas, PINs
  • • Preguntas de seguridad
  • • Patrones de desbloqueo

2. Algo que tienes (Possession)

  • • Tokens de hardware (YubiKey)
  • • Teléfono móvil (SMS, apps)
  • • Tarjetas de acceso

3. Algo que eres (Inherence)

  • • Huellas dactilares
  • • Reconocimiento facial
  • • Escaneo de iris/retina

Ejemplo: Flujo de Autenticación

// Frontend - Login Request
async function login(username, password) {
  const response = await fetch('/api/auth/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password })
  });
  
  const { token } = await response.json();
  // Guardar token (¡VULNERABLE si es localStorage!)
  localStorage.setItem('authToken', token);
  return token;
}

// Backend - Verificar Credenciales (Node.js/Express)
app.post('/api/auth/login', async (req, res) => {
  const { username, password } = req.body;
  
  // 1. Buscar usuario
  const user = await db.users.findOne({ username });
  if (!user) {
    return res.status(401).json({ error: 'Credenciales inválidas' });
  }
  
  // 2. Verificar contraseña (usando bcrypt)
  const isValid = await bcrypt.compare(password, user.passwordHash);
  if (!isValid) {
    return res.status(401).json({ error: 'Credenciales inválidas' });
  }
  
  // 3. Generar token JWT
  const token = jwt.sign(
    { userId: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: '24h' }
  );
  
  res.json({ token, user: { id: user.id, username: user.username } });
});

Autorización en Profundidad

Modelos de Control de Acceso

Role-Based Access Control (RBAC)

Los permisos se asignan a roles, y los usuarios son asignados a roles.

// Definir roles y permisos
const roles = {
  admin: ['read', 'write', 'delete', 'manage_users'],
  editor: ['read', 'write'],
  viewer: ['read']
};

// Middleware de autorización
function authorize(requiredPermission) {
  return (req, res, next) => {
    const userRole = req.user.role; // del token JWT
    const permissions = roles[userRole] || [];
    
    if (!permissions.includes(requiredPermission)) {
      return res.status(403).json({ 
        error: 'No tienes permisos para esta acción' 
      });
    }
    
    next();
  };
}

// Uso en rutas
app.delete('/api/posts/:id', 
  authenticate,  // primero autenticación
  authorize('delete'),  // luego autorización
  deletePost
);

Attribute-Based Access Control (ABAC)

Los permisos se basan en atributos del usuario, recurso y contexto.

// Política ABAC
function canEditDocument(user, document, context) {
  return (
    // El usuario es el propietario
    document.ownerId === user.id ||
    // El usuario es admin
    user.role === 'admin' ||
    // El usuario está en el departamento y el doc no está bloqueado
    (user.department === document.department && 
     !document.locked &&
     context.time < document.deadline)
  );
}

// Uso
app.put('/api/documents/:id', authenticate, async (req, res) => {
  const document = await db.documents.findById(req.params.id);
  const context = { time: new Date(), ip: req.ip };
  
  if (!canEditDocument(req.user, document, context)) {
    return res.status(403).json({ error: 'Acceso denegado' });
  }
  
  // Proceder con la edición
});

Vulnerabilidades Comunes

Broken Authentication

  • • Contraseñas débiles o predeterminadas
  • • Tokens de sesión expuestos en URLs
  • • Falta de rate limiting en login
  • • Session fixation attacks
  • • Almacenamiento inseguro de credenciales

Broken Access Control

  • IDOR (Insecure Direct Object References)
  • • Falta de validación de permisos en APIs
  • • Privilege escalation (vertical/horizontal)
  • • Path traversal sin restricciones
  • • Missing function level access control

Mejores Prácticas

Autenticación Segura

  • ✓ Implementar Multi-Factor Authentication (2FA/MFA)
  • ✓ Usar bcrypt/argon2 para hashear contraseñas
  • ✓ Implementar rate limiting y CAPTCHA
  • ✓ Usar HTTPS para todo el tráfico
  • ✓ Implementar account lockout tras intentos fallidos
  • ✓ Usar tokens seguros (JWT con firma HMAC/RSA)

Autorización Segura

  • ✓ Verificar permisos en CADA petición (server-side)
  • ✓ Usar principio de mínimo privilegio
  • ✓ Implementar separation of duties
  • ✓ Denegar por defecto (whitelist approach)
  • ✓ Registrar todos los eventos de autorización
  • ✓ Revisar y auditar permisos regularmente

Ejemplo: Sistema Completo

// middleware/auth.js
const jwt = require('jsonwebtoken');

// Middleware de autenticación
function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'Token no proporcionado' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    return res.status(401).json({ error: 'Token inválido' });
  }
}

// Middleware de autorización
function requireRole(...allowedRoles) {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: 'No autenticado' });
    }
    
    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({ 
        error: 'No tienes permisos',
        required: allowedRoles,
        current: req.user.role
      });
    }
    
    next();
  };
}

// routes/posts.js
app.get('/api/posts', authenticate, getPosts);
app.post('/api/posts', authenticate, requireRole('editor', 'admin'), createPost);
app.delete('/api/posts/:id', authenticate, requireRole('admin'), deletePost);

// Resource-level authorization
app.put('/api/posts/:id', authenticate, async (req, res) => {
  const post = await db.posts.findById(req.params.id);
  
  // Solo el autor o admin puede editar
  if (post.authorId !== req.user.id && req.user.role !== 'admin') {
    return res.status(403).json({ error: 'No puedes editar este post' });
  }
  
  // Actualizar post
  await db.posts.update(req.params.id, req.body);
  res.json({ success: true });
});

Recursos Adicionales

Siguiente Paso

Aprende sobre la implementación segura de sesiones y tokens

Secure Session Management