Ir al contenido

Seguridad

  • JWT con algoritmo HS256.
  • Tokens de acceso y refresh.
  • Blacklist de tokens y revocación masiva por usuario en Redis.
  • Contraseñas hasheadas con bcrypt.

Implementación: backend/app/core/security.py.

El sistema usa roles y permisos:

  • User → UserRole → Role → Permission.
  • Un permiso se define por (modulo, accion).

require_permission (backend/app/core/deps.py:47) protege cada endpoint:

def require_permission(modulo: str, accion: str):
async def _check(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_session),
) -> User:
if not current_user.user_roles:
raise AuthorizationError("Sin rol asignado")
perm_repo = PermissionRepository(db)
for ur in current_user.user_roles:
has = await perm_repo.user_has_permission(ur.role_id, modulo, accion)
if has:
return current_user
raise AuthorizationError("Permiso denegado")
return _check

Para evitar que un usuario con permiso global budgets:leer acceda a presupuestos ajenos, se usa require_budget_access (backend/app/api/budget_ownership.py):

async def require_budget_access(
budget_id: uuid.UUID,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_session),
) -> User:
budget = await db.get(Budget, budget_id)
if budget is None or budget.deleted_at is not None:
raise HTTPException(status_code=404, detail="Presupuesto no encontrado")
if budget.project_id is None:
raise HTTPException(status_code=404, detail="Presupuesto no vinculado a ningún proyecto")
return current_user

Este guard se encadena en endpoints sensibles como /recalculate y /espacios.

budget_editable_guard.py centraliza las reglas que impiden modificar un presupuesto según su estado:

if budget.estado in ("approved", "finalizado"):
raise ConflictError(f"No se puede {operation} un presupuesto en estado '{budget.estado}'")

Según AGENTS.md, todo cambio de código pasa por @security-specialist:

Ventana de terminal
hermes -p security-specialist

Audita:

  • El diff de la rama actual.
  • Dependencias vulnerables (pip-audit, npm audit).
  • No corrige, solo reporta.

Revisar vulnerabilidades con pip-audit:

Ventana de terminal
cd backend
uv run pip-audit
Ventana de terminal
cd frontend
npm audit
  1. No exponer información interna en mensajes de error (p. ej. nombres de tablas).
  2. Sanitizar fórmulas de mediciones: no usar eval(), usar AST seguro (backend/app/services/budget_breakdown_service.py:35).
  3. Validar ownership en recursos multi-tenant.
  4. No almacenar secretos en el repositorio; usar .env.
  5. CORS restringido a orígenes configurados (backend/app/core/config.py).
  6. Rate limiting en login.

Variables críticas en .env:

  • SECRET_KEY: clave para firmar JWT.
  • DATABASE_URL
  • REDIS_URL
  • CORS_ORIGINS

Nunca commitear .env real.