El fallo más común en los portales es invisible para cualquier escáner
Un portal de clientes. Un usuario real, con acceso correcto, abre un documento suyo. La dirección es algo como /api/documentos/4187.
Cambia el número. 4186. Y ve el contrato firmado de otra empresa.
Es el primer punto de la clasificación de OWASP para API, se llama Broken Object Level Authorization, y lo encontramos en buena parte de los portales a los que nos llaman.
Por qué ningún escáner lo encuentra
Porque técnicamente no hay ningún error. El programa hace exactamente lo que se le ha pedido: se le ha pedido el documento 4186, y devuelve el documento 4186. No se cae, no produce avisos, responde 200.
Una herramienta automática busca patrones conocidos: entradas sin filtrar, versiones viejas, configuraciones equivocadas. No puede saber que ese documento no es de quien lo está pidiendo, porque esa información está en vuestro modelo de negocio, no en el código.
Cómo se escribe por error
Así:
if (!usuario_autenticado()) {
return null;
}
return db()->fila('SELECT * FROM documentos WHERE id = ?', [$id]);
Un control hay, y es el que todos esperan ver: sin acceso no se pasa. Pero la pregunta a la que responde la última línea es «¿existe el documento 4186?», no «¿el documento 4186 es de quien lo está pidiendo?».
Cómo se cierra
$usuario = usuario_autenticado();
if (!$usuario) {
return null;
}
return db()->fila(
'SELECT * FROM documentos WHERE id = ? AND cliente_id = ?',
[$id, $usuario->cliente_id]
);
La corrección no añade un control: quita la posibilidad de olvidarlo.
Mientras la autorización sea un if escrito al lado de la consulta, tarde o temprano alguien escribirá una consulta nueva sin ese if al lado — quizá dentro de dos años, quizá un proveedor distinto. Metida dentro de la consulta, la pregunta equivocada ya no se puede formular.
Y hay un efecto secundario útil: quien prueba un número al azar recibe un 404, así que ni siquiera aprende que ese número corresponde a algo.
Cómo se comprueba en el vuestro
Hace falta una persona que lo pruebe, con dos cuentas de prueba y media hora. Abrid algo con la primera cuenta, coged la dirección, y volved a probar con la segunda. Si veis el documento de la primera, lo habéis encontrado.
No hace falta ser técnico para hacer esta prueba. Solo hace falta hacerla.
$ ls ./journal --altri
Para leer después
Portal de clientes: cuándo compensa y cuándo es un gasto inútil
Non è una questione di dimensione dell'azienda. È una questione di quante volte alla settimana rispondi alla stessa domanda.
¿Cuánto te cuesta un contacto? Si no lo sabes, estás gastando a ciegas
Il conto è una divisione. Il difficile non è farla: è avere i due numeri giusti, e quasi nessuno ce li ha.
Un presupuesto dado antes del prototipo es una apuesta
Perché chiediamo di costruire le schermate principali prima di dire quanto costa tutto il resto — e perché conviene anche a chi paga.
