Saltar a contenido

Capítulo 32 — Cloud Storage Security Rules: Protegiendo archivos en Firebase

Recursos visuales propuestos

Antes de desarrollar este capítulo conviene distinguir entre recursos pedagógicos para explicar conceptos de seguridad de archivos y recursos técnicos que representan la arquitectura real de autorización. El flujo de autorización para un archivo, la comparación entre archivo público y privado, la organización de carpetas protegidas, los ejemplos de restricciones por tipo de archivo y los casos de uso deben presentarse como imágenes didácticas, porque ayudan a fijar criterios de diseño y a visualizar escenarios frecuentes sin necesidad de describir internamente todos los componentes de la plataforma. En cambio, la arquitectura Cliente → Storage → Security Rules, el flujo completo de autorización, la integración entre Authentication, Firestore y Storage, y la arquitectura de protección del almacenamiento del proyecto oficial deben representarse como diagramas SVG, ya que requieren mostrar identidad, rutas, motor de evaluación, metadatos, datos auxiliares y decisiones de acceso entre múltiples servicios.[cite:1][cite:2]

Imágenes didácticas

  1. Flujo de autorización para un archivo. Conviene como imagen didáctica porque ayuda a comprender rápidamente el paso de solicitud, evaluación y decisión.[cite:1]
  2. Comparación entre archivo público y privado. Funciona mejor como imagen didáctica por su carácter comparativo y conceptual.
  3. Organización de carpetas protegidas. Debe ser imagen didáctica porque el objetivo principal es explicar diseño lógico de paths y segmentación de acceso.
  4. Ejemplos de restricciones por tipo de archivo. Se entiende mejor como imagen didáctica al mostrar reglas por MIME, extensión y tamaño.[cite:1][cite:2]
  5. Casos de uso. Conviene presentarlos como imágenes didácticas para resumir fotografías, evidencias, expedientes y recursos multimedia.

Diagramas SVG

  1. Arquitectura Cliente → Storage → Security Rules. Debe ser SVG porque representa el pipeline de autorización path-based en Cloud Storage.[cite:1]
  2. Flujo completo de autorización. Debe ser SVG porque integra request, resource, request.resource, auth y resultado booleano.[cite:2]
  3. Integración entre Authentication, Firestore y Storage. Debe ser SVG porque muestra cómo las reglas de Storage pueden apoyarse en autenticación y documentos de Firestore.[cite:2]
  4. Arquitectura de protección del almacenamiento del proyecto oficial. Debe ser SVG porque requiere representar módulos, carpetas virtuales, claims, metadatos y reglas diferenciadas por rol.

Objetivos de aprendizaje

Al finalizar este capítulo, el lector será capaz de:

  • Comprender qué son las Cloud Storage Security Rules y por qué son la capa central de autorización para archivos en Firebase.[cite:1]
  • Explicar cómo Storage evalúa solicitudes usando request, resource, request.resource, auth, metadata y time.[cite:2]
  • Diseñar reglas de acceso para documentos, imágenes, videos, credenciales, evidencias y expedientes según rol, institución, path y metadatos.
  • Diferenciar correctamente Cloud Storage Security Rules de Firestore Security Rules y elegir dónde validar cada aspecto de la seguridad.
  • Integrar Authentication, Firestore, Custom Claims y Cloud Functions en una arquitectura profesional de protección de archivos.[cite:1][cite:2]
  • Construir y justificar el sistema completo de reglas del proyecto oficial del libro con enfoque de mínimo privilegio y separación entre archivos públicos y privados.

Introducción

En muchas aplicaciones modernas, la información más sensible no vive solo en la base de datos. También existe en forma de archivos: fotografías, constancias, expedientes, evidencias, firmas digitales, documentos PDF, credenciales visuales, videos y materiales multimedia. Proteger únicamente Firestore pero dejar abierto el almacenamiento es como cerrar la puerta principal y dejar todas las ventanas abiertas.

Cloud Storage para Firebase permite almacenar objetos binarios a escala, pero precisamente por esa flexibilidad requiere un sistema de autorización riguroso. La documentación oficial explica que Firebase Security Rules para Cloud Storage permiten gestionar permisos basados en rutas y validar solicitudes para restringir accesos o limitar características de los archivos, como su tamaño o tipo.[cite:1]

Esto es especialmente importante porque una petición a Storage no es simplemente “leer un documento” o “actualizar un campo”. Aquí se trabaja con objetos completos, paths, tamaños, metadatos y tipos MIME. Por eso, las reglas de Storage tienen una lógica similar a las de Firestore, pero se aplican sobre un recurso distinto y con capacidades diferentes.[cite:1][cite:2]

En este capítulo se explicará cómo funciona el motor de reglas de Cloud Storage, cómo diseñar paths seguros, cómo validar archivos mediante metadatos y cómo integrar Authentication, Firestore y Cloud Functions para construir una arquitectura de almacenamiento segura. Todo se aplicará al proyecto transversal del libro, que necesita proteger fotografías de usuarios, firmas digitales, credenciales, expedientes, evidencias, tareas, PDFs y recursos multimedia con permisos distintos según el rol del usuario.

Desarrollo completo

Introducción conceptual

¿Qué son las Storage Security Rules?

Las Storage Security Rules son reglas declarativas que se ejecutan en los servidores de Firebase y determinan si una operación sobre un archivo en Cloud Storage está permitida o denegada. La documentación oficial las describe como reglas de autorización por archivo y por path, además de mecanismo de validación de datos para nombres, rutas y propiedades del archivo como contentType y size.[cite:1]

¿Por qué son necesarias?

Porque un archivo puede contener información muy sensible y, a diferencia de un documento de Firestore, su impacto visual o legal puede ser inmediato. Un PDF con expedientes, una firma digital o una credencial no solo es un dato: puede ser evidencia, identidad o información privada crítica.

Las reglas son necesarias para decidir:

  • quién puede leer un archivo;
  • quién puede subirlo;
  • quién puede reemplazarlo;
  • quién puede borrarlo;
  • qué tipo de archivo puede subirse;
  • cuánto puede pesar;
  • en qué carpeta virtual puede vivir;
  • qué metadatos debe contener.

Diferencias entre Firestore Rules y Storage Rules

Ambas usan el lenguaje de Firebase Security Rules y comparten conceptos como request.auth, match, allow y funciones personalizadas.[cite:1][cite:2] Sin embargo, el recurso evaluado es distinto.

En Firestore, la unidad típica es un documento con campos estructurados. En Storage, la unidad es un objeto binario con path y metadatos. Por eso, Storage pone mucho énfasis en:

  • path del archivo;
  • tamaño;
  • contentType;
  • metadata personalizada;
  • separación entre recurso existente y recurso propuesto.

Flujo de autorización para archivos

El flujo general es:

  1. El cliente intenta leer, subir, modificar metadatos o borrar un archivo.
  2. Cloud Storage identifica el path solicitado.
  3. Evalúa las reglas match que aplican a esa ruta.[cite:1]
  4. Construye el contexto request, incluyendo autenticación, path, tiempo y el nuevo recurso en caso de escritura.[cite:2]
  5. Evalúa la condición booleana correspondiente.
  6. Si la condición es verdadera, permite la operación; si es falsa, la deniega.

Funcionamiento interno

Motor de evaluación

La documentación de condiciones deja claro que el bloque fundamental en Storage Rules es la condición, una expresión booleana que determina si una operación se permite o no.[cite:2]

Toda regla finalmente responde una sola pregunta: ¿la expresión es true? Si no, el acceso se rechaza.

request

La documentación oficial enumera varias propiedades del objeto request: auth, params, path, resource y time.[cite:2] En términos prácticos, request representa la solicitud entrante y su contexto de evaluación.

resource

resource describe el archivo existente en Cloud Storage, incluyendo propiedades como name, bucket, size, contentType, metadata, timeCreated, updated y hashes del objeto.[cite:2] Es la fotografía del recurso actual.

auth

request.auth contiene contexto de autenticación cuando el usuario está autenticado, incluyendo uid y claims del token JWT en request.auth.token; si el usuario no está autenticado, request.auth es null.[cite:1][cite:2]

request.auth

Aunque suele hablarse de auth de forma general, en reglas la referencia correcta es request.auth. Es el punto de entrada para autorizaciones por usuario, por rol o por claims personalizados.[cite:1][cite:2]

request.resource

En escrituras, la documentación indica que request.resource contiene un subconjunto de los metadatos que se escribirán si la operación es permitida. Puede usarse junto con resource para validar integridad y restricciones de aplicación.[cite:2]

Esto es esencial al controlar:

  • tamaño de carga;
  • tipo MIME;
  • metadata obligatoria;
  • cambios permitidos en metadata;
  • reemplazo de archivos existentes.

metadata

resource.metadata y request.resource.metadata permiten acceder a metadatos personalizados definidos por la aplicación.[cite:2] Esta característica es extremadamente poderosa porque permite reforzar autorización más allá del path. Por ejemplo, un archivo puede contener en metadata el ownerId, institutionId, groupId o visibility.

time

request.time representa el tiempo del servidor en el momento de evaluación.[cite:2] Puede usarse para restricciones temporales, como permitir cierta carga solo dentro de una ventana de entrega o bloquear operaciones después de una fecha límite.

Operaciones

Storage agrupa operaciones de lectura y escritura, y también permite razonar sobre creación, actualización y borrado aunque el vocabulario práctico más habitual en las reglas sea read y write.

read

Autoriza descarga o acceso de lectura al archivo.

write

Agrupa operaciones de subida, reemplazo, metadata update y borrado.

create

Conceptualmente es una escritura cuando el objeto aún no existe. Es importante distinguirla en el diseño aunque la regla se exprese sobre escritura general, porque muchas veces crear debe tener criterios diferentes a reemplazar o borrar.

update

Corresponde al reemplazo del contenido del archivo o de sus metadatos. Aquí resource y request.resource deben compararse para decidir qué cambios se aceptan.

delete

Es la eliminación del objeto. Normalmente debería estar más restringida que la mera lectura.

Validaciones

Usuario autenticado

El patrón básico documentado por Firebase es:

allow read, write: if request.auth != null;

Esto exige autenticación para cualquier operación sobre un path dado.[cite:1]

Propietario del archivo

La documentación también muestra el patrón de archivos privados por usuario usando prefijos que contienen el UID, por ejemplo /users/{userId}/profilePicture.png, autorizando escritura solo si request.auth.uid == userId.[cite:2]

Roles

Los roles pueden venir en request.auth.token, por ejemplo:

  • superadmin
  • admin
  • director
  • teacher
  • student
  • parent
  • guest

Restricción por institución

En aplicaciones multiempresa o multiinstitución, el path o la metadata deben incluir el identificador organizacional. De lo contrario, la autorización se vuelve mucho más frágil.

Restricción por carpeta

Storage trabaja sobre paths, por lo que la estructura de carpetas virtuales es parte del modelo de seguridad. Una carpeta mal diseñada equivale a una regla más difícil de escribir y de auditar.

Restricción por extensión

La documentación muestra que es posible restringir nombres con expresiones regulares, por ejemplo permitiendo solo archivos .txt mediante imageId.matches(".*\\.txt").[cite:2] Esto demuestra que el nombre del objeto también forma parte de la superficie de validación.

Restricción por tipo MIME

Firebase documenta el uso de request.resource.contentType.matches('image/.*') para permitir solo imágenes.[cite:1][cite:2]

Restricción por tamaño

También se documenta explícitamente la validación de request.resource.size < 5 * 1024 * 1024 para limitar un upload a menos de 5 MB.[cite:1][cite:2]

Restricción por nombre de archivo

Además de extensiones, puede exigirse una convención segura de nombres para impedir caracteres extraños, prefijos indebidos o formatos no controlados.

Restricción por metadatos

Los metadatos personalizados permiten añadir una segunda capa de control. Por ejemplo, exigir que todo expediente PDF lleve:

  • ownerId
  • institutionId
  • documentType
  • visibility

Organización

Protección por carpetas virtuales

En Cloud Storage no existen carpetas reales como sistema jerárquico tradicional; existen nombres de objeto con prefijos. Aun así, la organización por carpetas virtuales es fundamental porque las reglas hacen match sobre esos paths.[cite:1]

Ejemplo:

  • /public/
  • /users/{uid}/profile/
  • /institutions/{institutionId}/credentials/
  • /institutions/{institutionId}/evidences/
  • /institutions/{institutionId}/expedientes/

Protección por usuarios

Es ideal para recursos estrictamente privados o personales, como fotografías de perfil, firma personal o archivos de un alumno concreto.

Protección por módulos

También es útil organizar por dominio funcional:

  • profiles
  • credentials
  • evidences
  • documents
  • multimedia

Protección para aplicaciones multiempresa

En aplicaciones multiempresa, cada path sensible debería contener explícitamente el institutionId o tenantId. Esto simplifica reglas, auditoría y aislamiento organizacional.

Integración

Authentication

Storage Security Rules se integra directamente con Firebase Authentication. La documentación oficial indica que request.auth se llena con el uid y claims del usuario autenticado, y es null si no existe autenticación.[cite:1][cite:2]

Firestore

La documentación de condiciones explica que las reglas de Storage pueden usar firestore.get() y firestore.exists() para evaluar autorización contra documentos de Cloud Firestore.[cite:2] Esto permite, por ejemplo, leer membresías, relaciones de amistad, grupos o permisos institucionales antes de permitir acceso a un archivo.

Custom Claims

Como los claims viajan en request.auth.token, son ideales para roles relativamente estables, como superadmin, director o teacher.[cite:2]

Cloud Functions

Cloud Functions complementa las reglas cuando se necesita lógica privilegiada. Por ejemplo:

  • generar una credencial PDF;
  • mover archivos entre zonas seguras;
  • firmar metadata de confianza;
  • limpiar archivos temporales;
  • crear URLs de acceso controlado.

Optimización

Rendimiento

La optimización de reglas en Storage no consiste solo en escribir menos líneas, sino en diseñar paths y metadatos que permitan decidir rápido y con pocas dependencias externas. Cuando una regla necesita consultar Firestore, aumenta complejidad operacional y dependencia entre servicios.[cite:2]

Organización de reglas

Un archivo profesional debe agruparse por zonas del bucket y reutilizar funciones. No conviene repetir veinte veces el mismo criterio de autenticación, rol o institución.

Reutilización mediante funciones

La documentación oficial indica que las reglas soportan funciones personalizadas y que estas mejoran mantenibilidad a medida que crece la complejidad del ruleset.[cite:2]

Pruebas

Firebase recomienda integrar desarrollo, pruebas y despliegue de reglas como parte del flujo profesional. Las reglas no deben publicarse “por intuición”. Deben probarse con escenarios reales de lectura, subida, reemplazo y borrado.[cite:2]

Depuración

La depuración exige saber si falló:

  • autenticación;
  • path;
  • claim;
  • metadata;
  • tipo MIME;
  • tamaño;
  • lectura auxiliar a Firestore.

Ejemplos paso a paso

Ejemplo 1: carpeta privada autenticada

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /internal/{fileName} {
      allow read, write: if request.auth != null;
    }
  }
}

Este patrón está alineado con la documentación cuando exige autenticación para acceso privado.[cite:1][cite:2]

Ejemplo 2: fotografía de perfil por usuario

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/profilePicture.png {
      allow read;
      allow write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Firebase muestra este caso como ejemplo de “user private”, donde el path contiene el identificador del usuario.[cite:2]

Ejemplo 3: validar imágenes de hasta 5 MB

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

Este ejemplo proviene directamente de la documentación oficial.[cite:1][cite:2]

Ejemplo 4: acceso de grupo con metadata

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /files/{groupId}/{fileName} {
      allow read: if request.auth != null
                  && resource.metadata.owner == request.auth.token.groupId;
      allow write: if request.auth != null
                   && request.auth.token.groupId == groupId;
    }
  }
}

Este patrón también está documentado por Firebase para escenarios de grupo privado usando claims y metadata.[cite:2]

Ejemplo 5: autorización apoyada en Firestore

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if request.auth != null &&
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.uid));
    }
  }
}

La documentación muestra este patrón para permitir que solo amigos vean las fotos de un usuario, usando firestore.exists().[cite:2]

Proyecto transversal: arquitectura de seguridad de Storage

El proyecto oficial del libro requiere proteger múltiples tipos de archivo con criterios distintos.

Roles del sistema

  • superadmin
  • admin
  • director
  • teacher
  • student
  • parent
  • guest

Principios arquitectónicos

  1. Todo archivo sensible vive dentro de un path con institutionId.
  2. Todo archivo personal vive además dentro de un path con uid o actor principal.
  3. Los recursos públicos se separan estrictamente de los privados.
  4. Las URLs no sustituyen reglas; el control principal vive en Security Rules.
  5. Los archivos críticos no se crean ni actualizan libremente desde cliente si pueden afectar integridad institucional.

Estructura de carpetas propuesta

/public/
/institutions/{institutionId}/profiles/{userId}/photo.jpg
/institutions/{institutionId}/signatures/{userId}/signature.png
/institutions/{institutionId}/credentials/{userId}/{credentialId}.pdf
/institutions/{institutionId}/records/{studentId}/{fileName}
/institutions/{institutionId}/evidences/{groupId}/{studentId}/{fileName}
/institutions/{institutionId}/tasks/{taskId}/{fileName}
/institutions/{institutionId}/documents/admin/{fileName}
/institutions/{institutionId}/media/{module}/{fileName}

Funciones reutilizables

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {

    function isSignedIn() {
      return request.auth != null;
    }

    function uid() {
      return request.auth.uid;
    }

    function role() {
      return request.auth.token.role;
    }

    function institution() {
      return request.auth.token.institutionId;
    }

    function sameInstitution(institutionId) {
      return isSignedIn() && institution() == institutionId;
    }

    function isSuperAdmin() {
      return isSignedIn() && request.auth.token.superadmin == true;
    }

    function isAdmin(institutionId) {
      return sameInstitution(institutionId) && (role() == 'admin' || role() == 'director');
    }

    function isTeacher(institutionId) {
      return sameInstitution(institutionId) && role() == 'teacher';
    }

    function isStudent(institutionId) {
      return sameInstitution(institutionId) && role() == 'student';
    }

    function isParent(institutionId) {
      return sameInstitution(institutionId) && role() == 'parent';
    }

Fotografías de usuarios

    match /institutions/{institutionId}/profiles/{userId}/{fileName} {
      allow read: if sameInstitution(institutionId) || isSuperAdmin();
      allow write: if (uid() == userId && sameInstitution(institutionId))
                   || isAdmin(institutionId)
                   || isSuperAdmin();
    }

Justificación: las fotos pueden ser visibles internamente dentro de la institución, pero solo el propio usuario o un rol administrativo deben poder reemplazarlas.

Firmas digitales

    match /institutions/{institutionId}/signatures/{userId}/{fileName} {
      allow read: if uid() == userId || isAdmin(institutionId) || isSuperAdmin();
      allow write: if uid() == userId || isSuperAdmin();
    }

Las firmas tienen sensibilidad alta. No conviene abrir lectura general dentro de la institución.

Credenciales

    match /institutions/{institutionId}/credentials/{userId}/{credentialId} {
      allow read: if uid() == userId || isAdmin(institutionId) || isSuperAdmin();
      allow write: if false;
    }

Justificación: las credenciales digitales deben emitirse desde Cloud Functions con permisos privilegiados, no desde clientes.

Expedientes

    match /institutions/{institutionId}/records/{studentId}/{fileName} {
      allow read: if uid() == studentId
                  || isAdmin(institutionId)
                  || isTeacher(institutionId)
                  || isSuperAdmin();
      allow write: if isAdmin(institutionId) || isSuperAdmin();
    }

Evidencias escolares

    match /institutions/{institutionId}/evidences/{groupId}/{studentId}/{fileName} {
      allow read: if uid() == studentId
                  || isTeacher(institutionId)
                  || isAdmin(institutionId)
                  || isSuperAdmin();
      allow write: if uid() == studentId
                   && isStudent(institutionId)
                   && request.resource.size < 20 * 1024 * 1024
                   && (
                     request.resource.contentType.matches('image/.*')
                     || request.resource.contentType.matches('application/pdf')
                   );
    }

Tareas

    match /institutions/{institutionId}/tasks/{taskId}/{fileName} {
      allow read: if sameInstitution(institutionId) || isSuperAdmin();
      allow write: if isTeacher(institutionId) || isAdmin(institutionId) || isSuperAdmin();
    }

Documentos administrativos PDF

    match /institutions/{institutionId}/documents/admin/{fileName} {
      allow read: if isAdmin(institutionId) || isSuperAdmin();
      allow write: if isAdmin(institutionId)
                   && request.resource.contentType.matches('application/pdf')
                   && request.resource.size < 10 * 1024 * 1024
                   || isSuperAdmin();
    }

Recursos multimedia

    match /institutions/{institutionId}/media/{module}/{fileName} {
      allow read: if sameInstitution(institutionId) || isSuperAdmin();
      allow write: if isTeacher(institutionId)
                   || isAdmin(institutionId)
                   || isSuperAdmin();
    }
  }
}

Casos reales

Fotografías de perfil

Las fotografías de perfil suelen necesitar un modelo mixto: escritura privada y lectura más amplia dentro del ecosistema, según el caso de negocio. No se debe asumir que porque “es solo una foto” no requiere protección. Puede contener información personal identificable.

Evidencias escolares

Son archivos típicamente subidos por alumnos y revisados por docentes. Deben restringirse por rol, institución, tamaño y tipo MIME. Además, conviene impedir que otro alumno acceda a evidencias ajenas.

Credenciales digitales

La credencial es un documento institucional de confianza. Por esa razón, la arquitectura recomendada es lectura autorizada y generación controlada desde backend.

Expedientes

Los expedientes suelen ser el caso más sensible de todo el bucket. Deben tratarse como almacenamiento privado y altamente regulado.

Recursos multimedia

Estos pueden requerir permisos más flexibles, pero no necesariamente públicos. Un video formativo interno o material docente no debe confundirse con un recurso abierto a internet.

Documentos administrativos

PDFs administrativos, actas o constancias requieren un control mucho más cercano al de expedientes que al de material multimedia.

Comparaciones técnicas

Firestore Rules vs Storage Rules

Criterio Firestore Rules Storage Rules
Unidad protegida Documento Archivo/objeto
Datos evaluados Campos estructurados Path, metadata, tamaño, tipo MIME
Contexto principal resource.data [cite:2] resource y request.resource [cite:2]
Uso típico acceso a datos acceso a binarios

Archivo público vs archivo privado

Criterio Público Privado
Requiere autenticación No necesariamente [cite:2] Sí, normalmente [cite:1][cite:2]
Casos de uso assets, contenido abierto fotos, expedientes, evidencias
Riesgo menor si está bien clasificado alto si se expone
Diseño recomendado separar en zona dedicada reglas de mínimo privilegio

Path-based vs metadata-based

Criterio Path-based Metadata-based
Simplicidad Alta Media
Trazabilidad Alta Alta
Flexibilidad Media Alta
Uso ideal usuario/institución visibles en ruta permisos complementarios, visibilidad, tipo de recurso

Claim vs consulta a Firestore

Criterio Custom Claim firestore.get() / firestore.exists()
Velocidad conceptual Más simple Más flexible
Dependencia externa No Sí [cite:2]
Escenario ideal roles estables membresías, relaciones dinámicas
Complejidad operativa Menor Mayor

Buenas prácticas

  • Aplicar el principio de mínimo privilegio en cada zona del bucket.
  • Separar físicamente los archivos públicos de los privados mediante paths claros.
  • Diseñar rutas que incluyan información suficiente para autorizar correctamente, como institutionId y userId.
  • Validar tamaño y contentType en uploads, no confiar solo en el cliente.[cite:1][cite:2]
  • Usar metadata personalizada cuando el negocio lo justifique, pero sin depender de ella como único control cuando el path ya puede expresar el dominio.
  • Reservar escrituras de archivos críticos, como credenciales o documentos oficiales, para Cloud Functions privilegiadas.
  • Mantener funciones reutilizables para roles, autenticación e institución.[cite:2]
  • Usar Firestore en reglas solo cuando realmente aporte valor y justificación arquitectónica.[cite:2]
  • Gestionar URLs con cuidado: una URL de acceso no debe convertirse en un sustituto informal de la autorización.
  • Versionar y desplegar reglas como parte del proyecto, no como cambios manuales aislados.

Errores comunes

  • Pensar que conocer la URL del archivo equivale a tener permiso legítimo.
  • Mezclar archivos públicos y privados en la misma zona lógica del bucket.
  • Permitir write amplio solo porque “el cliente ya valida”.
  • No validar contentType ni tamaño.[cite:1][cite:2]
  • Basar toda la seguridad en el nombre del archivo sin considerar rol o institución.
  • No incluir institutionId en paths multiempresa.
  • Permitir reemplazo de archivos críticos por parte del usuario sin restricciones.
  • No limitar lectura de firmas digitales o expedientes.
  • Abusar de lecturas a Firestore desde reglas sin una estrategia clara.[cite:2]
  • Diseñar reglas diferentes para Storage y Firestore que terminan contradiciéndose en el mismo flujo de negocio.

Checklist para producción

Antes de publicar Storage en producción, revisar:

  • ¿El ruleset usa rules_version = '2';?
  • ¿Existen zonas públicas claramente separadas de las privadas?
  • ¿Los archivos sensibles exigen autenticación?
  • ¿Las rutas incluyen institutionId, userId u otra información necesaria para autorizar correctamente?
  • ¿Los uploads validan tamaño y tipo MIME?[cite:1][cite:2]
  • ¿Los archivos críticos solo pueden crearse o modificarse desde backend privilegiado?
  • ¿Las reglas reflejan realmente los roles del negocio?
  • ¿Las firmas, credenciales y expedientes tienen protección reforzada?
  • ¿El uso de firestore.get() o firestore.exists() está justificado?[cite:2]
  • ¿Se probaron operaciones de lectura, subida, reemplazo y borrado para cada rol?
  • ¿Las URLs y descargas no están sustituyendo el modelo formal de autorización?

Resumen

Las Cloud Storage Security Rules son la capa que protege archivos en Firebase mediante autorización por ruta y validación de solicitudes. La documentación oficial destaca que permiten restringir accesos por usuario o por path y también validar características como tamaño, nombre, contentType y metadata del archivo.[cite:1][cite:2]

Su motor de evaluación trabaja con varios elementos clave: request.auth aporta identidad y claims del usuario autenticado, resource representa el objeto ya existente y request.resource describe el nuevo recurso propuesto durante escrituras, incluyendo metadatos relevantes.[cite:1][cite:2] A partir de esos elementos, las reglas pueden autorizar o denegar lecturas, subidas, reemplazos y borrados.

En aplicaciones reales, la seguridad de Storage depende tanto de las reglas como del diseño de paths. Un bucket bien organizado separa archivos públicos y privados, incorpora institutionId y userId cuando corresponde, y reserva los archivos de alta confianza —como credenciales, firmas o expedientes— para flujos controlados por backend. Además, cuando el negocio lo exige, Storage puede integrarse con Firestore mediante firestore.get() y firestore.exists() para aplicar criterios adicionales de autorización.[cite:2]

En el proyecto oficial del libro, esta arquitectura permite proteger fotografías, firmas digitales, credenciales, expedientes, evidencias, tareas, PDFs y multimedia con permisos distintos para superadministrador, administrador, director, docente, alumno, padre de familia e invitado. Ese es el objetivo profesional del capítulo: convertir el almacenamiento de archivos en una capa segura, mantenible y coherente con el resto de la arquitectura Firebase.

Conceptos clave

  • Cloud Storage Security Rules.[cite:1]
  • Autorización path-based.[cite:1]
  • request.auth.[cite:1][cite:2]
  • request.resource.[cite:2]
  • resource.[cite:2]
  • resource.metadata.[cite:2]
  • request.resource.contentType.[cite:1][cite:2]
  • request.resource.size.[cite:1][cite:2]
  • MIME type.
  • Carpeta virtual.
  • Metadata personalizada.[cite:2]
  • firestore.get().[cite:2]
  • firestore.exists().[cite:2]
  • Custom Claims.[cite:2]
  • Mínimo privilegio.

Preguntas de repaso

  1. ¿Qué son las Cloud Storage Security Rules y qué problema resuelven?[cite:1]
  2. ¿Qué diferencias principales existen entre Firestore Rules y Storage Rules?[cite:1][cite:2]
  3. ¿Qué información aporta request.auth durante la evaluación de una regla?[cite:1][cite:2]
  4. ¿Qué diferencia existe entre resource y request.resource?[cite:2]
  5. ¿Por qué conviene validar contentType y tamaño de archivo en reglas?[cite:1][cite:2]
  6. ¿Qué ventajas ofrece incluir institutionId y userId en el path del archivo?
  7. ¿Cuándo conviene usar metadata personalizada para reforzar autorización?[cite:2]
  8. ¿Qué ventajas y riesgos tiene integrar Storage Rules con Firestore mediante firestore.get() o firestore.exists()?[cite:2]
  9. ¿Por qué la creación de credenciales y expedientes sensibles debería delegarse a Cloud Functions?
  10. ¿Qué zonas del bucket del proyecto oficial deberían ser públicas y cuáles privadas?

Ejercicios prácticos

  1. Diseña una estructura de paths para separar archivos públicos, privados y multiinstitución.
  2. Escribe una regla para que cada usuario solo pueda subir su propia foto de perfil.[cite:2]
  3. Crea una regla que permita solo imágenes menores a 5 MB y documentos PDF menores a 10 MB.[cite:1][cite:2]
  4. Implementa protección para expedientes estudiantiles con acceso restringido por institución y rol.
  5. Diseña reglas para evidencias escolares que permitan upload al alumno y lectura al docente.
  6. Crea una estrategia de metadatos personalizados para ownerId, institutionId y documentType.
  7. Implementa una regla que consulte Firestore para validar membresía antes de permitir lectura de un recurso compartido.[cite:2]
  8. Diseña el ruleset para firmas digitales con lectura muy restringida.
  9. Propón un flujo donde Cloud Functions genere credenciales PDF y Storage Rules impida al cliente reemplazarlas.
  10. Elabora una auditoría de seguridad de un bucket que hoy usa allow read, write: if request.auth != null; en toda su estructura.

Bibliografía y referencias oficiales