Seguridad de APIs · Lección 12

Autorización de API, scopes y mass assignment

Una API acepta datos estructurados de clientes que escriben otros, y ese es exactamente el problema. En una web con formularios controlas los campos que se envían; en una API el cliente manda el JSON que quiera, con los campos que quiera. Si el servidor confía en que el cuerpo trae solo lo que el formulario "oficial" pondría, un cliente curioso añade un campo de más —rol, saldo, es_admin— y el servidor lo guarda. Se llama mass assignment y es una de las formas más rápidas de pasar de cliente a administrador. Esta lección separa autenticación de autorización, fija qué son los scopes y la autorización a nivel de campo, y corrige el fallo en una API real que tú levantas.

Al terminar sabrás

  • Separar autenticación (quién eres) de autorización (qué puedes hacer), y ver por qué una API necesita las dos.
  • Explicar qué acota un scope de un token y qué no: permisos, no identidad.
  • Distinguir autorización a nivel de objeto de autorización a nivel de campo.
  • Reconocer un mass assignment y explotarlo para escalar a administrador en el laboratorio.
  • Corregirlo con una lista de campos permitidos y fijando los campos privilegiados en el servidor.
  • Escribir una verificación que falle mientras el fallo esté abierto y pase cuando lo cierres.

1Por qué importa

La mayor parte del código de autorización que se escribe protege el acceso a un recurso: ¿puede este usuario ver este pedido? Es la pregunta de la lección de control de acceso roto, y es imprescindible. Pero hay una segunda pregunta que casi nadie escribe y que una API deja abierta por omisión: ¿puede este usuario modificar este campo de este recurso? Leer y escribir no son el mismo permiso, y dentro de escribir, no todos los campos valen lo mismo. Cambiar tu propio nombre es una cosa; cambiar tu propio rol es otra completamente distinta, aunque las dos sean "editar mi perfil".

El mass assignment aparece porque los frameworks facilitan justo lo peligroso. Convertir el cuerpo JSON en un objeto y volcarlo entero a la base de datos es una línea, y funciona a la primera para el caso feliz. El campo que sobra no da error: se guarda en silencio. El día que alguien descubre que puede añadir "rol": "admin" al mismo cuerpo con el que se registra, la comodidad de esa línea se cobra la aplicación entera. No hace falta romper nada: la API hace exactamente lo que le pidió el atacante.

El objetivo real

No estás aprendiendo a validar formularios. Estás aprendiendo a decidir, campo por campo, quién tiene derecho a escribir qué, y a no delegar esa decisión en la forma del cuerpo que te manda un cliente que no controlas. La regla es simple de enunciar y difícil de mantener: el servidor decide los campos privilegiados, nunca el cliente.

2Conceptos

Vocabulario mínimo
  • Autenticación: demostrar quién eres. Un token válido responde a esto.
  • Autorización: decidir qué te está permitido hacer. Es una decisión por operación, no una propiedad del token.
  • Scope: la lista de operaciones que un token concreto habilita (pedidos:leer, perfil:escribir). Acota permisos, no identidad.
  • Autorización a nivel de objeto: ¿este usuario puede tocar este recurso? (control de acceso roto, IDOR).
  • Autorización a nivel de campo: dentro de un recurso que sí puede tocar, ¿qué campos puede escribir?
  • Mass assignment: el servidor copia el cuerpo entero al objeto, así que el cliente escribe campos que debía fijar el servidor.
  • Lista de campos permitidos (allow-list): la corrección; solo se leen del cuerpo los campos que el cliente tiene derecho a escribir.

3Explicación profunda

Autenticación y autorización se confunden porque suelen llegar juntas en el mismo token, pero resuelven problemas distintos. La autenticación termina en una afirmación: "esta petición viene de la usuaria Ana". A partir de ahí, la autorización empieza de cero en cada operación: que la petición sea de Ana no dice si Ana puede borrar el pedido 42, ni si puede ascenderse a administradora. Un sistema que trata "estar autenticado" como "tener permiso" ha colapsado las dos preguntas en una, y esa es la raíz de casi todos los fallos de esta fase.

Los scopes son la forma estándar de escribir permisos en un token de acceso. Un token emitido para una app de solo lectura lleva pedidos:leer y nada más; aunque el usuario dueño del token sea administrador, ese token no puede escribir, porque el scope acota lo que el token habilita, con independencia de quién sea su portador. Esto es mínimo privilegio aplicado a credenciales: la app de informes recibe un token que no puede hacer daño aunque se filtre. El error clásico es emitir un único token con todos los scopes "para no complicarse", que es como darle a cada empleado la llave maestra del edificio.

Dentro de la autorización hay dos niveles que conviene no mezclar. El nivel de objeto pregunta si puedes tocar un recurso concreto: es lo que falla en un IDOR, cuando cambias el id de la URL y lees el pedido de otro. El nivel de campo pregunta, una vez que sí puedes tocar el recurso, qué partes de él puedes escribir. El mass assignment vive en este segundo nivel: tienes todo el derecho a editar tu propio perfil —el objeto es tuyo— pero no a editar el campo rol de tu propio perfil. La API que solo comprueba "¿es tuyo el objeto?" y luego vuelca el cuerpo entero deja el nivel de campo sin ninguna defensa.

El mecanismo técnico del mass assignment es siempre el mismo: un binding automático. update(cuerpo), Object.assign(user, body), User(**body), model.attributes = params. Todas esas líneas toman las claves del cuerpo que envió el cliente y las escriben como atributos del objeto. Si el cuerpo trae rol, se escribe rol. El framework no distingue entre un campo que el cliente tenía derecho a poner y uno que no: para él son claves de un diccionario. La defensa no puede ser "recordar no mandar rol"; tiene que ser que el servidor nunca lea rol del cuerpo, aunque venga.

Hay dos formas de cerrarlo, y la diferencia importa. La lista de campos permitidos (allow-list) enumera lo que sí se lee del cuerpo y descarta todo lo demás; es segura por defecto, porque un campo nuevo y peligroso que alguien añada mañana no está en la lista y no se escribe. La lista de campos prohibidos (deny-list) enumera lo que no se lee; es frágil, porque el día que se añade un campo sensible y nadie actualiza la lista, queda abierto. En seguridad, por defecto se rechaza: la allow-list es la única de las dos que falla de forma segura.

4Ejemplo sencillo

# El formulario de alta de un gimnasio

Lo que el formulario "oficial" te deja rellenar:
    nombre, correo, contrasena

Lo que de verdad viaja si lo rellenas tu a mano:
    nombre, correo, contrasena, tipo_socio=VIP, cuota=0

# El recepcionista con mass assignment

copia entera la ficha que pusiste, sin mirar.
Tu escribiste "tipo_socio: VIP" en un hueco en blanco
y ahora eres socio VIP con cuota cero. Nadie te lo dio:
lo escribiste tu, y el sistema lo copio sin preguntar.

# El recepcionista con lista de campos permitidos

solo mira nombre, correo y contrasena. El resto de la
ficha lo ignora. El tipo de socio lo fija el, segun sus
reglas, no segun lo que tu escribiste.
El fallo no es que exista un campo privilegiado. Es que el sistema deja que lo rellene quien no debe, porque copia la ficha entera sin decidir qué campos acepta de quién.

5Ejemplo técnico

El laboratorio de esta fase expone POST /registro. Míralo primero como lo ve un cliente honesto y luego como lo ve alguien que añade un campo:

PeticiónCuerpo enviadoLo que guarda la API vulnerable
Cliente honesto{"usuario":"leo","clave":"..."}rol: cliente (el valor por defecto del servidor)
Cliente que prueba{"usuario":"mallory","clave":"...","rol":"admin"}rol: admin (el valor que puso el cliente)
Cliente que exagera{"usuario":"eva","clave":"...","saldo":999999}saldo: 999999 (dinero que nadie ingresó)

La API arranca con un valor por defecto correcto (rol: cliente) y luego lo pisa con lo que trae el cuerpo. El defecto no protege nada si después se sobrescribe con la entrada del cliente. Escrito como riesgo con actor, vía, activo y consecuencia: "Cualquier cliente puede darse de alta como administrador añadiendo el campo rol al cuerpo de /registro, porque el servidor fusiona el cuerpo completo, lo que le da control total de la API."

6Diagrama

Un cuerpo JSON con un campo rol de más entra a un binding que lo fusiona entero; el registro resultante queda con rol admin. Una lista de campos permitidos descarta el campo rol antes de fusionar. cuerpo del cliente usuario, clave, rol=admin update(cuerpo) binding sin filtro solo {usuario, clave} lista de permitidos registro rol=admin escalada registro rol=cliente servidor fija el rol mismo cuerpo, dos caminos
El campo de más solo hace daño si el binding lo lee. La lista de campos permitidos lo descarta antes de tocar el registro, así que da igual que el cliente lo envíe.
Ver el mismo diagrama como código Mermaid (editable)
flowchart LR
    C[cuerpo: usuario, clave, rol=admin] -->|binding sin filtro| U[update cuerpo]
    C -->|lista de permitidos| P[solo usuario, clave]
    U --> A[registro rol=admin · escalada]
    P --> B[registro rol=cliente · servidor fija el rol]

7Código

Este es el corazón del fallo tal como está en el laboratorio. El valor por defecto correcto se pierde en la línea siguiente:

# VULNERABLE — el cuerpo entero pisa los valores del servidor
def registro(cuerpo):
    registro = {"rol": "cliente", "saldo": 0}
    registro.update(cuerpo)          # rol y saldo del cuerpo GANAN
    registro["usuario"] = cuerpo["usuario"]
    USUARIOS[cuerpo["usuario"]] = registro
    return 201, registro

La corrección no añade una comprobación: cambia quién decide. El servidor lee del cuerpo solo los campos públicos y fija los privilegiados por su cuenta:

# CORRECTO — lista de campos permitidos; el servidor fija rol y saldo
PERMITIDOS = {"usuario", "clave"}

def registro(cuerpo):
    limpio = {k: cuerpo[k] for k in PERMITIDOS if k in cuerpo}
    if "usuario" not in limpio or "clave" not in limpio:
        return 400, {"error": "faltan campos obligatorios"}
    registro = {
        "usuario": limpio["usuario"],
        "clave": limpio["clave"],
        "rol": "cliente",   # lo fija el servidor, no el cuerpo
        "saldo": 0,        # idem
    }
    USUARIOS[registro["usuario"]] = registro
    return 201, {"usuario": registro["usuario"], "rol": registro["rol"]}

Fíjate en que rol ya no aparece leído del cuerpo en ninguna parte. Esa es la prueba visual de que el fallo está cerrado: si el nombre del campo no está en el código del lado del servidor como algo que se lee de la entrada, el cliente no puede fijarlo por mucho que lo mande.

8Qué puede salir mal

Los errores clásicos

Confiar en el formulario del cliente. "El campo rol no está en nuestra app, así que nadie lo va a mandar." El cliente de tu app no es el único que habla con tu API; cualquiera con curl manda el cuerpo que quiera.

Usar una lista de campos prohibidos. Filtrar rol y es_admin parece suficiente hasta que alguien añade rol_id o grupo y nadie actualiza la lista. Lo que no está enumerado como permitido debe rechazarse, no al revés.

Validar solo en la creación. El mass assignment reaparece en PATCH /perfil: editar el perfil propio es legítimo, escribir el rol dentro de esa edición no lo es. Cada endpoint que hace binding necesita su propia lista.

Confundir "el objeto es mío" con "puedo escribir todo el objeto". Autorización de objeto y de campo son comprobaciones distintas. Pasar la primera no exime de la segunda.

9Cómo lo abusaría un atacante

Vista desde el otro lado

Quien ataca una API empieza por leer qué campos devuelve. Si GET /perfil/ana responde con un campo rol, ya sabe el nombre exacto del campo que le interesa escribir. La API le está enseñando su propio esquema. El siguiente paso es probar ese mismo nombre en cualquier endpoint que acepte un cuerpo: registro, edición de perfil, creación de cualquier recurso.

La prueba es barata y silenciosa. Manda el cuerpo normal más el campo sospechoso y mira la respuesta: si el campo vuelve con el valor que puso, hay mass assignment. No hay ninguna alarma que salte, porque desde el punto de vista de la API es una petición válida y bien formada. Por eso este fallo puede vivir años en producción: nunca produce un error, solo produce un administrador de más de vez en cuando.

Y encadena hacia arriba. Un saldo escrito a mano es fraude directo; un rol: admin abre todos los endpoints administrativos, que suelen tener aún menos validación porque "solo los usan los administradores". El primer campo de más es la llave; lo que hay detrás de la puerta es el resto de la aplicación.

10Cómo defenderlo

Qué hacer con esto mañana
  • En cada endpoint que reciba un cuerpo, lee solo una lista explícita de campos permitidos. Descarta el resto sin avisar o rechaza con 400; nunca lo escribas.
  • Fija los campos privilegiados en el servidor: rol, saldo, estado, propietario. Que no se lean nunca de la entrada.
  • Separa el modelo de entrada del modelo de persistencia. Un DTO de entrada con solo los campos públicos hace el fallo imposible por construcción.
  • Aplica autorización de objeto y de campo como dos comprobaciones. Ser dueño del recurso no autoriza a escribir cualquier campo de él.
  • Da a cada credencial el scope mínimo. Un token de solo lectura no debería poder llegar a un endpoint de escritura aunque su dueño sea administrador.
  • Escribe un test de regresión que mande rol: admin en el registro y exija que la respuesta y la base guarden rol: cliente.

11Laboratorio

Estado: laboratorio local lab-api-vuln
Targethttp://localhost:8096
Autorizaciónsistema local creado por ti para entrenamiento
Esta API tiene fallos a propósito y es tuya. Todo lo que se practica aquí se practica aquí dentro. Ninguna de estas técnicas debe usarse contra una API que no sea tuya o para la que no tengas autorización escrita.

Levanta la API vulnerable y confirma que responde:

cd cursos/seguridad/labs/lab-api-vuln docker compose up -d --build curl -s http://localhost:8096/salud

Ahora escala a administrador con un solo campo de más en el cuerpo del registro:

atacar → observar → defender → verificar
curl -s -X POST http://localhost:8096/registro \ -H 'Content-Type: application/json' \ -d '{"usuario":"mallory","clave":"1234","rol":"admin","saldo":999999}' { "rol": "admin", "saldo": 999999, "usuario": "mallory", "clave": "1234" } # mass assignment: pusiste rol y saldo, y la API los guardo curl -s http://localhost:8096/perfil/mallory # confirmado: eres admin sin que nadie te ascendiera

Ahora defiéndelo. Edita api/servidor.py, cambia el _registro para que lea solo usuario y clave del cuerpo y fije rol y saldo en el servidor, y reconstruye:

docker compose up -d --build curl -s -X POST http://localhost:8096/registro -H 'Content-Type: application/json' -d '{"usuario":"tester","clave":"x","rol":"admin"}'

La respuesta ahora debe traer rol: cliente. Si aún dice admin, tu lista de permitidos no está filtrando. Cuando termines:

docker compose down -v

12Ejercicios

Autenticación o autorización

Para cada frase, di si describe un fallo de autenticación o de autorización: (1) un token caducado sigue siendo aceptado; (2) un cliente cambia el id de la URL y lee el pedido de otro; (3) un usuario se asigna el rol admin al registrarse; (4) la API acepta un token firmado con una clave que no es la suya; (5) un token de solo lectura consigue escribir.

Autenticación responde "¿quién eres?"; autorización responde "¿qué puedes hacer?".
Si el problema es que el sistema se equivoca sobre la identidad, es autenticación. Si acierta la identidad pero permite de más, es autorización.
El caso (5) es autorización a nivel de permiso del token: sabe quién eres, pero no debería dejarte escribir.
Solución

(1) autenticación: acepta una prueba de identidad que ya no vale. (2) autorización de objeto. (3) autorización de campo (mass assignment). (4) autenticación: valida mal la firma. (5) autorización: el scope del token debería impedirlo.

Clave: AutN · AutZ · AutZ · AutN · AutZ. Los casos (2), (3) y (5) son tres niveles distintos de autorización: objeto, campo y scope.

Cierra el mass assignment con una allow-list

Con el lab-api-vuln levantado, modifica _registro en api/servidor.py para que use una lista de campos permitidos. El registro debe aceptar solo usuario y clave del cuerpo, y fijar rol y saldo en el servidor. Reconstruye y demuestra que rol: admin enviado por el cliente ya no tiene efecto.

El problema está en la línea registro.update(cuerpo): copia todo el cuerpo.
Construye el registro campo a campo desde una lista PERMITIDOS = {"usuario", "clave"}, sin leer nada más del cuerpo.
Después de docker compose up -d --build, repite el ataque y comprueba que la respuesta trae rol: cliente.
Solución

La corrección es la del bloque de código de la lección: leer solo los campos de PERMITIDOS y fijar rol y saldo con literales del servidor. La verificación:

# tras reconstruir, esto debe devolver rol: cliente
curl -s -X POST http://localhost:8096/registro \
  -H 'Content-Type: application/json' \
  -d '{"usuario":"t1","clave":"x","rol":"admin"}' | grep rol

Clave: la señal de éxito es que rol ya no se lee del cuerpo en el código y que la respuesta al ataque devuelve cliente. Si sigue diciendo admin, el binding sin filtrar sigue ahí.

El mismo fallo en PATCH

Imagina que la API añade PATCH /perfil/<usuario> para que un cliente edite su propio nombre y correo. Diseña ese endpoint sin reintroducir el mass assignment, y explica por qué una allow-list de creación no basta y hace falta una específica para la edición. Investiga cómo lo resuelven dos frameworks reales (por ejemplo strong parameters de Rails y los DTO de entrada en un framework tipado) y compáralos.

La allow-list de edición suele ser distinta de la de creación: en PATCH puede que ni usuario se deje cambiar.
Busca "strong parameters" y "mass assignment protection"; casi todos los frameworks tienen un nombre para esto.
La diferencia clave entre los dos enfoques es dónde se declara la lista: en el controlador o en el tipo de la petición.
Solución

PATCH /perfil debe leer solo nombre y correo del cuerpo; ni rol, ni saldo, ni siquiera usuario (la identidad viene del token, no del cuerpo). La allow-list de creación no sirve porque los campos escribibles cambian según la operación: al crear se fija la clave, al editar el perfil normalmente no. Rails lo resuelve con strong parameters (params.require(:perfil).permit(:nombre, :correo)), una allow-list declarada en el controlador; un framework tipado lo resuelve con un DTO de entrada que solo tiene esos dos campos, de modo que el binding no puede escribir nada más porque el tipo no lo contiene. El segundo es más robusto: el compilador impide el error.

Clave: una allow-list por operación, la identidad desde el token y nunca desde el cuerpo, y preferir un DTO de entrada tipado que hace el mass assignment imposible por construcción en vez de por disciplina.

Red Team · descubre el nombre del campo y escálalo

Dentro del lab-api-vuln, y solo dentro de él: sin mirar el código del servidor, descubre qué campo controla el rol usando solo las respuestas de la API, y luego úsalo para registrarte como administrador. Documenta cómo supiste el nombre del campo.

Empieza por lo que la API te devuelve: registra un usuario normal y mira todos los campos de la respuesta.
El campo que quieres escribir suele aparecer en la salida de /perfil. La API enseña su esquema.
Reenvía el registro con ese campo añadido y compara el rol de la respuesta con el del usuario normal.
Solución

Registrar un usuario normal y pedir GET /perfil/<usuario> revela un campo rol con valor cliente. Ese es el nombre. Reenviar POST /registro con "rol":"admin" en el cuerpo devuelve un registro con rol: admin. La API filtró su propio esquema en las respuestas y no filtró la entrada: las dos mitades del mismo fallo de validación.

Clave: el nombre del campo salió de la salida de la API, no de adivinar. Sobre-exponer campos en las respuestas y no filtrar la entrada es un fallo doble; los cierras en las lecciones de este mismo laboratorio.

Blue Team · detecta el intento en los logs

Genera varios registros, algunos honestos y otros con rol o saldo en el cuerpo, y mira docker compose logs api. Con el formato de log actual, ¿puedes distinguir un registro honesto de uno que intenta escalar? Enumera qué campos tendría que registrar la API para que un intento de mass assignment fuera detectable.

El log de acceso por defecto trae método, ruta y código. Compáralo con lo que necesitarías para ver el intento.
El cuerpo no aparece en el log de acceso, y menos mal: llevaría la clave. Pero entonces el intento es invisible.
La detección no es registrar el cuerpo entero, sino registrar el hecho concreto: "se ignoró un campo no permitido".
Solución

Con el log de acceso no se distingue: todos los registros son POST /registro con código 201. El intento vive en el cuerpo, que no se registra. La forma correcta de hacerlo detectable no es loggear el cuerpo (contiene la clave), sino que la propia allow-list emita un evento cuando descarta un campo no permitido: "registro de mallory intentó fijar rol". Eso registra el intento sin registrar el secreto, y da una señal clara: un cliente que manda campos privilegiados que no le tocan es sospechoso aunque la petición se procese bien.

Clave: el entregable es la lista de campos a registrar cuando la allow-list descarta algo: usuario, endpoint, nombre del campo rechazado. Nunca el valor, nunca la clave.

Architecture Challenge · separar entrada de persistencia

Diseña la capa de entrada de una API para que el mass assignment sea imposible por construcción, no por disciplina. Define: qué separa el modelo que recibe la petición del modelo que se guarda, dónde se fijan los campos privilegiados, cómo se aplican los scopes del token a la escritura, y qué comprobación automática en el pipeline garantiza que un endpoint nuevo no reintroduzca el fallo.

Si el tipo que recibe la petición no contiene el campo rol, ningún binding puede escribirlo.
Los campos privilegiados se fijan en la capa de servicio, a partir del token y las reglas, no de la petición.
Un test genérico puede recorrer todos los endpoints de escritura y comprobar que ninguno acepta campos fuera de su DTO.
Solución

Una propuesta razonable: un DTO de entrada por operación con solo los campos públicos, distinto del modelo de persistencia; el handler convierte el DTO en el modelo fijando rol, propietario y estado desde el token y las reglas de negocio, nunca desde el cuerpo; el scope del token se comprueba antes de escribir, de modo que un token de lectura ni llega al handler de escritura. En el pipeline, un test de contrato que envía campos extra a cada endpoint de escritura y exige que se ignoren o se rechacen; y una regla que falle la build si un handler hace binding directo del cuerpo al modelo de persistencia sin pasar por un DTO.

Clave: no hay una única respuesta. Se evalúa que el fallo sea imposible por el tipo (DTO de entrada) y no por recordar filtrar, que los campos privilegiados se fijen del lado del servidor, y que haya una puerta automática que impida reintroducirlo.

13Preguntas de comprensión

Comprobación

¿Qué es exactamente mass assignment?

El binding automático toma las claves del cuerpo como atributos del objeto. Si el cuerpo trae rol, se escribe rol, sin distinguir quién tenía derecho a ponerlo.

Estás autenticado como cliente normal. ¿Por qué eso no basta para estar seguro?

Que la petición sea tuya no dice qué puedes escribir. La autorización empieza de cero en cada operación, y a nivel de campo.

¿Cuál es la corrección correcta para el mass assignment de /registro?

La allow-list es segura por defecto: un campo peligroso que se añada mañana no está en la lista y no se escribe. Rechazar solo rol es una deny-list frágil.

¿Qué acotan los scopes de un token de acceso?

El scope es mínimo privilegio aplicado a la credencial: un token de solo lectura no puede escribir aunque su dueño sea administrador.

0 / 4

14Reto adicional

Autorización de campo con dos roles

Amplía el laboratorio en tu cabeza (o en el código): un administrador legítimo sí debe poder fijar el rol de otro usuario mediante la API, pero un cliente no. Diseña cómo el mismo endpoint acepta el campo rol del cuerpo solo cuando quien llama es administrador, y lo ignora cuando es un cliente. ¿Dónde se toma esa decisión, y por qué no puede depender de un campo del cuerpo?

La allow-list puede depender de quién llama: no es la misma lista para un admin que para un cliente.
El rol de quien llama viene del token verificado, no de un campo que el propio cuerpo pueda afirmar.
Si la decisión dependiera de "soy_admin": true en el cuerpo, habrías reinventado el mass assignment.
Solución

La lista de campos permitidos se elige según el rol de quien llama, y ese rol se lee del token autenticado, nunca del cuerpo. Para un cliente, la lista es {usuario, clave}; para un administrador probado, se amplía con rol. La decisión se toma en el servidor, después de verificar el token y antes de tocar el registro. Si dependiera de cualquier dato del cuerpo, el atacante afirmaría ser admin en el mismo cuerpo y volveríamos al principio: la autoridad tiene que venir de algo que el cliente no pueda falsificar.

Clave: lo interesante es que la corrección del mass assignment no es "prohibir rol para siempre", sino "decidir la allow-list según una autoridad que el cliente no controla". El campo privilegiado puede existir; lo que no puede es que lo autorice el propio cuerpo.

15Resumen

Puntos clave
  • Autenticación dice quién eres; autorización decide qué puedes hacer, y se comprueba en cada operación.
  • Hay autorización de objeto (¿puedo tocar este recurso?) y de campo (¿qué partes puedo escribir?). El mass assignment vive en la segunda.
  • El mass assignment es un binding automático que copia el cuerpo entero al objeto, escribiendo campos que debía fijar el servidor.
  • La corrección es una lista de campos permitidos, no una de prohibidos: por defecto se rechaza.
  • Los campos privilegiados —rol, saldo, propietario— se fijan en el servidor a partir del token, nunca se leen del cuerpo.
  • Separar el modelo de entrada del de persistencia hace el fallo imposible por construcción.
¿Qué línea de código es el corazón de un mass assignment?
Un binding sin filtro: update(cuerpo), Object.assign(user, body), User(**body). Copia el cuerpo entero al objeto.
¿Por qué una lista de campos permitidos es mejor que una de prohibidos?
Porque falla de forma segura: un campo peligroso que se añada mañana no está en la lista y no se escribe. La deny-list se abre en silencio al olvidar actualizarla.
¿De dónde debe salir el rol de quien llama para autorizar una operación?
Del token autenticado, nunca de un campo del cuerpo. Si el cuerpo pudiera afirmarlo, sería mass assignment otra vez.
¿Qué acota un scope de token y qué no?
Acota qué operaciones permite el token; no cambia quién es su dueño. Un token de solo lectura no escribe aunque su dueño sea admin.

16Mis notas

Cierre de la lección

Estas notas se guardan solo en este navegador. No se envían a ningún servidor. Expórtalas desde el panel de progreso si cambias de máquina.

17Recursos

Los comentarios se cargan solo si los pides, desde GitHub Discussions. No se carga nada de terceros mientras no pulses.