Una API puede autenticar correctamente a una persona y aun así enseñarle la factura, el informe o el proyecto de otra organización. El inicio de sesión responde quién solicita; la autorización por recurso decide si ese sujeto puede realizar esa acción sobre ese objeto concreto.
OWASP sitúa la autorización rota a nivel de objeto, conocida como BOLA, como API1:2023. El patrón aparece cuando el servidor recibe un identificador y recupera el objeto sin comprobar la relación entre identidad, acción y recurso.
El identificador no concede permiso
Cambiar un entero secuencial por un UUID dificulta adivinar valores, pero no sustituye el control. Un identificador puede filtrarse en logs, enlaces, exportaciones o respuestas relacionadas. La regla debe aplicarse aunque el cliente presente un ID válido.
Una consulta peligrosa separa la carga del permiso:
invoice = invoices.find(request.invoice_id)
return invoice
Una consulta con ámbito incorpora la organización autorizada:
invoice = invoices.find(
id = request.invoice_id,
tenant_id = session.tenant_id
)
Después debe comprobar también la acción. Poder leer una factura no implica poder anularla. En dominios complejos, una política central puede expresar sujeto, acción, recurso y contexto, pero el endpoint sigue siendo responsable de invocarla.
Matriz de pruebas cruzadas
Para un recurso proyecto, prepara al menos dos organizaciones, varios usuarios y dos roles. La matriz mínima sería:
| Identidad | Recurso | Acción | Resultado esperado |
|---|---|---|---|
| Administrador A | proyecto de A | leer | permitido |
| Analista A | proyecto de A | editar | denegado si su rol es lectura |
| Administrador A | proyecto de B | leer | denegado |
| Administrador A | proyecto de B | editar | denegado |
| Usuario desactivado A | proyecto de A | leer | denegado |
| Proceso de servicio | proyecto asignado | exportar | permitido con alcance concreto |
Repite estas pruebas en rutas REST, variables GraphQL, descargas, operaciones masivas y relaciones anidadas. Un endpoint /organizaciones/A/proyectos/B no debe confiar en que el proyecto B pertenece a A porque la URL lo afirma.
Decide cómo responder sin filtrar existencia
En algunos sistemas conviene devolver 404 tanto para un objeto inexistente como para uno existente pero inaccesible, evitando confirmar su presencia. En otros, un 403 es útil para clientes internos. La elección debe ser coherente y estar documentada; los errores de API no deben revelar nombres de otras organizaciones ni detalles internos.
Registra el tipo de decisión, la política aplicada y un identificador de correlación. Evita escribir en logs datos sensibles completos o tokens. Una subida de denegaciones cruzadas puede indicar un cliente mal configurado o una exploración hostil y merece una alerta separada de los errores técnicos.
Controles de implementación
- deriva el ámbito de la identidad validada, no de un campo editable enviado por el cliente;
- filtra por tenant u organización en la capa de acceso a datos;
- comprueba permisos en cada función que acepta un identificador externo;
- aplica el mismo control a lectura, modificación, borrado y exportación;
- limita las identidades de servicio a recursos y acciones necesarios;
- conserva pruebas negativas como parte de la integración continua.
La prueba decisiva consiste en intercambiar identificadores entre dos organizaciones y confirmar que ninguna combinación no autorizada devuelve datos ni produce efectos. Autenticar es solo la entrada; la seguridad real se decide en cada recurso.