Un permiso a nivel de clase es una regla en el esquema de una clase que controla qué usuarios o roles pueden ejecutar cada operación en esa clase. Es el gate más externo de la seguridad en la capa de datos: antes de cualquier verificación por fila, la propia clase decide si este solicitante puede consultar, crear, actualizar o eliminar ahí — una regla, la tabla entera, verificada primero.
Puntos clave
| Pregunta | Respuesta |
|---|---|
| Qué es | Reglas de acceso por operación sobre la propia clase (tabla) |
| vs. ACLs | La CLP custodia la clase; las ACLs custodian cada fila — la solicitud pasa por ambas |
| Las operaciones | Find, get, count, create, update, delete, add field — cada una se configura por separado |
| Los defaults de oro | Exigir autenticación, bloquear el add field, jamás enviar la master key al cliente |
| El primo en SQL | GRANT/REVOKE sobre tablas y esquemas — misma idea, otra sintaxis |
El gate de la clase, declarado y sentido
Una CLP es configuración de esquema — aquí el payload REST que bloquea una clase Config en lectura pública y escritura solo desde el servidor:
PUT /schemas/Config
{
"classLevelPermissions": {
"find": { "*": true }, // cualquiera puede consultar
"get": { "*": true },
"create": {}, // nadie desde el lado del cliente
"update": { "role:admin": true }, // solo admins
"delete": {},
"addField": {} // esquema congelado
}
}
Lo que los clientes experimentan es el gate haciendo su trabajo — las lecturas fluyen, las escrituras mueren en la frontera de la clase antes de tocar dato alguno:
// JavaScript / Node.js — Back4app JS SDK
// The class gate in action: Config is read-only for clients (CLP),
// so reads succeed and writes never reach the data
const config = await new Parse.Query('Config').first(); // ✓ public read
const c = new Parse.Object('Config');
c.set('flag', true);
try {
await c.save(); // ✗ CLP blocks client writes to this class entirely
} catch (e) {
console.log(e.code); // 119: operation forbidden by class-level permissions
} // Flutter / Dart — Back4app Flutter SDK
// The class gate in action: reads allowed, client writes blocked by CLP
final config = ParseObject('Config')..set('flag', true);
final response = await config.save();
if (!response.success) {
print(response.error?.code); // 119: forbidden by class-level permissions
} // iOS / Swift — Back4app Swift SDK
// The class gate in action: reads allowed, client writes blocked by CLP
var config = Config()
config.flag = true
config.save { result in
if case .failure(let error) = result {
print(error) // operation forbidden by class-level permissions
}
} // Android / Kotlin — Back4app Android SDK
// The class gate in action: reads allowed, client writes blocked by CLP
val config = ParseObject("Config").apply { put("flag", true) }
config.saveInBackground { e ->
if (e != null) {
Log.d("CLP", "blocked: ${e.code}") // forbidden by class-level permissions
}
} Cómo trabajan juntos los permisos a nivel de clase y las ACLs
La escalera de granularidad: CLP vs. ACL vs. pointer permissions vs. campos protegidos
| Mecanismo | Alcance | Se declara en | Se verifica | Trabajo típico |
|---|---|---|---|---|
| Permiso a nivel de clase | Toda la clase, por operación | El esquema | Primero | ”Los clientes nunca escriben Config” |
| Pointer permission | Por objeto, vía regla de esquema | El esquema (anclada a un campo) | Segundo | ”Solo el owner toca sus filas” |
| ACL | Por objeto | En cada fila, como dato | Segundo | ”Esta nota: solo su autora” |
| Campos protegidos | Por columna | El esquema | En la lectura | ”Ocultar email de los demás usuarios” |
El idioma de diseño que se desprende: trazo grueso en el esquema, grano fino en las filas. Las clases con regla de acceso uniforme (config, catálogos, logs) solo necesitan el gate de la clase; las clases con datos por usuario agregan ACLs o pointer permissions debajo de él.
El mismo gate en otros motores
-- PostgreSQL: table-level privileges are CLPs by another name
GRANT SELECT ON films TO PUBLIC;
GRANT INSERT, UPDATE ON films TO role_editor;
REVOKE ALL ON launch_codes FROM PUBLIC;
Las bases de documentos lo reflejan con roles acotados a acciones a nivel de colección — un rol con find e insert sobre exactamente una colección. El concepto es universal; lo que cambia es la ergonomía: los grants de SQL y los documentos de roles se administran en código, mientras que las plataformas BaaS exponen la misma matriz como checkboxes en el dashboard.
Configuraciones recomendadas por tipo de contenido
| Tipo de contenido | Find/Get | Create | Update/Delete | Add field |
|---|---|---|---|---|
| Contenido público (catálogo, posts) | Público | Roles/servidor | Roles/servidor | Apagado |
| Datos del usuario (notas, pedidos) | Autenticado + ACLs | Autenticado | Acotado por ACL | Apagado |
| Config y flags | Público o autenticado | Nadie (solo servidor) | Rol de admin | Apagado |
| Logs y analítica | Nadie (solo servidor) | Autenticado (solo escritura) | Nadie | Apagado |
| Datos solo de admin | Rol de admin | Rol de admin | Rol de admin | Apagado |
Esa tabla es el checklist que la mayoría de los lanzamientos realmente necesita — nota la constante en la última columna y su regla hermana: la creación de clases desde el cliente apagada en producción, para que el esquema solo cambie a propósito.
Casos de uso comunes
- Congelar esquemas de producción. Add field apagado en todo; las clases dejan de aparecer y mutar por el tráfico de clientes.
- Datos de referencia de solo lectura. Catálogos y configuraciones legibles públicamente, escribibles solo por código del servidor — el patrón
Configde arriba. - Buzones de solo escritura. Clases de feedback y telemetría en las que los clientes pueden crear pero nunca leer — el gate inverso que el código de la capa de aplicación suele olvidar.
- Superficies de admin por rol. Update y delete reservados a un rol de admin mientras la app lee libremente.
- Defensa contra el dump clásico. El tristemente célebre one-liner — un curl con un app ID consultando una clase
Userabierta — muere en el gate de find cuando la clase exige autenticación.
¿Debería aplicarlo el gate de la clase o el código del servidor? Matriz de decisión
| Aplícalo con CLPs (+ ACLs) cuando… | Pásalo por código del servidor cuando… |
|---|---|
| La regla es “quién puede hacer qué, dónde” | La regla necesita lógica de negocio (“solo antes de que el pedido se envíe”) |
| Es uniforme por clase o por propietario | Atraviesa múltiples objetos o clases |
| Quieres que se aplique en todo camino, incluidos clientes nuevos | Quieres un único chokepoint auditado para un flujo sensible |
| Lo declarativo le gana a lo imperativo en la revisión | Validación, enriquecimiento o efectos secundarios van a bordo |
| El checkbox del dashboard es toda la especificación | La especificación es un párrafo de condiciones |
Se componen: el patrón endurecido para clases genuinamente sensibles bloquea las CLPs por completo y expone funciones del lado del servidor como la única puerta — el gate de la clase garantiza que nadie rodee el chokepoint.
Limitaciones y trade-offs
- La granularidad de clase es gruesa por definición. Todo lo que sea por fila pertenece a las ACLs y las pointer permissions; todo lo condicional pertenece a la validación del lado del servidor — las CLPs custodian, no razonan.
- Los defaults son permisivos para desarrollar. Las clases nuevas nacen abiertas para que los prototipos vuelen; la pasada previa al lanzamiento que aplica la tabla de arriba es una disciplina, no un automatismo.
- La master key lo ignora todo. Cada gate de este artículo es nulo allí donde viaja esa clave — por eso vive solo en el servidor, se usa por operación y jamás se envía al cliente.
- La superficie de enforcement debe ser completa. Las suscripciones en tiempo real y los endpoints especiales históricamente han tenido brechas — mantén la plataforma actualizada y prueba los gates desde un cliente real, no solo desde el dashboard.
- Los checkboxes también necesitan revisión. La seguridad declarativa solo es seguridad auditable si alguien la audita — la matriz de configuraciones pertenece a tu checklist de lanzamiento, no a la memoria tribal.
CLPs en Back4app
Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. Los permisos a nivel de clase son su superficie de seguridad de esquema en versión visual: cada clase en el dashboard lleva la matriz de operaciones como checkboxes — público, exige autenticación, por rol — más pointer permissions y campos protegidos, aplicados del lado del servidor en cada solicitud por igual en SDKs, REST y GraphQL. Debajo están las ACLs por objeto; encima, los triggers de Cloud Code para las reglas que necesitan lógica. Las guías de seguridad recorren la pasada previa al lanzamiento completa — la matriz de configuraciones de este artículo, aplicada clic a clic.
Preguntas frecuentes
¿Qué son los permisos a nivel de clase?
Reglas adjuntas al esquema de una clase (tabla/colección) que controlan qué usuarios o roles pueden realizar cada operación — find, get, count, create, update, delete, add field — sobre cualquier objeto de esa clase. Son el gate de acceso más grueso y el primero que se verifica: si la regla de la clase deniega una operación, ningún permiso por objeto llega a consultarse.
¿Cuál es la diferencia entre CLPs y ACLs?
Alcance y orden. Una CLP responde "quién puede tocar esta clase" — una regla para la tabla entera. Una ACL responde "quién puede tocar esta fila específica" — un dato que lleva cada objeto. Una solicitud debe pasar ambos gates: primero el de la clase, después el del objeto, y cualquiera puede denegar. Trazo grueso a nivel de clase, grano fino a nivel de objeto.
¿Qué es requiresAuthentication?
El ajuste intermedio entre público y roles enumerados: restringe una operación a cualquier usuario con sesión válida, sin nombrar usuarios ni roles específicos. Es el default correcto para la mayoría de los datos de una app — las solicitudes anónimas se rechazan, mientras que todo usuario autenticado pasa el gate de la clase y sigue a las verificaciones de ACL por objeto.
¿Qué son las pointer permissions?
Reglas a nivel de clase ancladas a un campo de puntero de usuario en el objeto — por ejemplo, "solo el usuario del campo owner puede leer o escribir". Actúan como una ACL virtual: el enforcement es por objeto, pero la regla se declara una sola vez en el esquema en lugar de almacenarse en cada fila. Se intersectan con las ACLs reales; ambas deben permitir la acción.
¿Qué son los campos protegidos (protected fields)?
Reglas a nivel de campo apiladas sobre el gate de la clase: columnas específicas — un correo, un score interno — ocultas para algunos solicitantes mientras el resto del objeto sigue legible. Convierten la escalera de permisos en tres peldaños sobre un mismo esquema: operaciones de toda la clase, acceso por objeto y visibilidad por campo.
¿Cuál es el equivalente en SQL de los permisos a nivel de clase?
Los privilegios de tabla y de esquema: GRANT SELECT, INSERT, UPDATE, DELETE sobre una tabla a un rol, REVOKE para quitarlos, más los derechos USAGE y CREATE a nivel de esquema. El concepto mapea uno a uno — un GRANT de tabla es un permiso a nivel de clase con otra sintaxis — y las bases de documentos lo reflejan con roles acotados a acciones por colección.
¿Deberían los clientes poder agregar campos o crear clases en producción?
No — este es el paso de hardening consensuado. La flexibilidad de esquema es una comodidad de desarrollo; en producción, deshabilita el permiso de add field en cada clase y apaga por completo la creación de clases desde el cliente, congelando el esquema frente a los clientes. Los cambios de esquema fluyen entonces por el dashboard o el código del servidor, donde pertenecen.
¿Bastan los permisos a nivel de clase para asegurar una app?
Son la primera capa, no la defensa completa. El stack estándar: las CLPs controlan las operaciones por clase, las ACLs o las pointer permissions acotan las filas, los campos protegidos ocultan las columnas sensibles y los triggers del lado del servidor validan las escrituras. Y una regla por encima de todas: la master key — que salta todos los gates — jamás viaja en código de cliente.