¿Qué son las reglas de seguridad de Firebase?
Firebase Security Rules ofrecen un lenguaje flexible basado en expresiones para definir quién tiene acceso de lectura y escritura a datos en Firestore, Realtime Database y Cloud Storage. Las reglas se evalúan en los servidores de Firebase, por lo que no pueden ser omitidas por clientes maliciosos.
Las reglas de seguridad están entre tus datos y usuarios maliciosos. Determinan qué datos se pueden leer y escribir, validan la estructura de datos y aplican lógica de negocio—sin requerir un servidor backend.
🔒 Por qué importan las reglas
- 🛡️ Protección de datos: Evita accesos no autorizados a datos sensibles.
- ✅ Validación de datos: Asegura que los datos cumplan tu esquema.
- 👤 Aislamiento de usuarios: Mantén privados los datos de cada usuario.
- 🚫 Limitación de abusos: Previene abuso con límites de tamaño y frecuencia.
Reglas de seguridad de Firestore
Estructura básica de las reglas de Firestore:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Rules go here
// Match a specific collection
match /users/{userId} {
// Allow read if user is authenticated
allow read: if request.auth != null;
// Allow write only to own document
allow write: if request.auth != null && request.auth.uid == userId;
}
}
}
Patrones comunes de reglas en Firestore
Ejemplos prácticos para escenarios comunes:
Datos propios del usuario
match /users/{userId} {
// Users can only read/write their own data
allow read, write: if request.auth != null && request.auth.uid == userId;
}
match /posts/{postId} {
// Anyone can read posts
allow read: if true;
// Only the author can create/update/delete
allow create: if request.auth != null
&& request.resource.data.authorId == request.auth.uid;
allow update, delete: if request.auth != null
&& resource.data.authorId == request.auth.uid;
}
Acceso basado en roles
match /admin/{document=**} {
// Only allow access if user has admin custom claim
allow read, write: if request.auth != null
&& request.auth.token.role == 'admin';
}
match /moderator-content/{docId} {
// Allow access to admins and moderators
allow read, write: if request.auth != null
&& request.auth.token.role in ['admin', 'moderator'];
}
Validación de datos
match /posts/{postId} {
allow create: if request.auth != null
// Required fields exist
&& request.resource.data.keys().hasAll(['title', 'content', 'authorId'])
// Title length validation
&& request.resource.data.title is string
&& request.resource.data.title.size() >= 1
&& request.resource.data.title.size() <= 100
// Content validation
&& request.resource.data.content is string
&& request.resource.data.content.size() <= 10000
// Author must be the current user
&& request.resource.data.authorId == request.auth.uid
// Timestamp must be server time
&& request.resource.data.createdAt == request.time;
allow update: if request.auth != null
&& resource.data.authorId == request.auth.uid
// Prevent changing certain fields
&& request.resource.data.authorId == resource.data.authorId
&& request.resource.data.createdAt == resource.data.createdAt;
}
Funciones en reglas de Firestore
Crea funciones reutilizables para reglas más limpias:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper function: Check if user is authenticated
function isAuthenticated() {
return request.auth != null;
}
// Helper function: Check if user owns the resource
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
// Helper function: Check if user has a specific role
function hasRole(role) {
return isAuthenticated() && request.auth.token.role == role;
}
// Helper function: Check if user is admin
function isAdmin() {
return hasRole('admin');
}
// Helper function: Validate string length
function isValidString(field, minLen, maxLen) {
return field is string
&& field.size() >= minLen
&& field.size() <= maxLen;
}
// Helper function: Get user document
function getUserData() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
}
// Use the functions
match /users/{userId} {
allow read: if isAuthenticated();
allow write: if isOwner(userId);
}
match /admin/{document=**} {
allow read, write: if isAdmin();
}
match /posts/{postId} {
allow read: if true;
allow create: if isAuthenticated()
&& isValidString(request.resource.data.title, 1, 100);
}
}
}
Reglas para subcolecciones
Asegura colecciones anidadas:
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
// Subcollection: user's private notes
match /notes/{noteId} {
// Inherit parent's rules - only owner can access
allow read, write: if request.auth.uid == userId;
}
// Subcollection: user's public posts
match /publicPosts/{postId} {
// Anyone can read, only owner can write
allow read: if true;
allow write: if request.auth.uid == userId;
}
}
// Wildcard to match any subcollection depth
match /users/{userId}/{document=**} {
allow read, write: if request.auth.uid == userId;
}
Reglas de seguridad de Cloud Storage
Asegura subidas y descargas de archivos:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// User profile images
match /users/{userId}/avatar.{ext} {
// Anyone can read profile images
allow read: if true;
// Only owner can upload, with restrictions
allow write: if request.auth != null
&& request.auth.uid == userId
// Only allow image files
&& request.resource.contentType.matches('image/.*')
// Max 5MB file size
&& request.resource.size < 5 * 1024 * 1024;
}
// User's private files
match /users/{userId}/private/{allPaths=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
// Public uploads (e.g., blog images)
match /public/{allPaths=**} {
// Anyone can read
allow read: if true;
// Only authenticated users can upload
allow write: if request.auth != null
&& request.resource.contentType.matches('image/.*')
&& request.resource.size < 10 * 1024 * 1024;
}
// Restrict file types
match /documents/{userId}/{fileName} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId
// Allow only PDF and common document formats
&& request.resource.contentType in [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
];
}
}
}
Reglas de seguridad de Realtime Database
Reglas basadas en JSON para Realtime Database:
{
"rules": {
// Default: deny all access
".read": false,
".write": false,
"users": {
"$userId": {
// Users can read their own data
".read": "$userId === auth.uid",
// Users can write their own data with validation
".write": "$userId === auth.uid",
// Validate user data structure
".validate": "newData.hasChildren(['name', 'email'])",
"name": {
".validate": "newData.isString() && newData.val().length <= 50"
},
"email": {
".validate": "newData.isString() && newData.val().matches(/^[^@]+@[^@]+$/)"
}
}
},
"posts": {
// Anyone can read posts
".read": true,
"$postId": {
// Only authenticated users can create posts
".write": "auth != null && (!data.exists() || data.child('authorId').val() === auth.uid)",
".validate": "newData.hasChildren(['title', 'content', 'authorId'])",
"authorId": {
".validate": "newData.val() === auth.uid"
}
}
},
"presence": {
"$userId": {
// Users can only update their own presence
".write": "$userId === auth.uid"
}
}
}
}
Probar reglas de seguridad
Prueba tus reglas antes de desplegar:
# Use the Firebase Emulator
firebase emulators:start
# Run rules tests
npm test
# Test file: tests/firestore.rules.test.js
const { initializeTestEnvironment, assertFails, assertSucceeds } = require('@firebase/rules-unit-testing');
let testEnv;
beforeAll(async () => {
testEnv = await initializeTestEnvironment({
projectId: 'demo-project',
firestore: {
rules: fs.readFileSync('firestore.rules', 'utf8')
}
});
});
afterAll(async () => {
await testEnv.cleanup();
});
test('users can read their own data', async () => {
const userId = 'user123';
const context = testEnv.authenticatedContext(userId);
const db = context.firestore();
await assertSucceeds(db.collection('users').doc(userId).get());
});
test('users cannot read other users data', async () => {
const context = testEnv.authenticatedContext('user123');
const db = context.firestore();
await assertFails(db.collection('users').doc('other-user').get());
});
test('unauthenticated users cannot write', async () => {
const context = testEnv.unauthenticatedContext();
const db = context.firestore();
await assertFails(db.collection('users').doc('test').set({ name: 'Test' }));
});
Desplegar reglas
Despliega tus reglas de seguridad:
# Deploy Firestore rules
firebase deploy --only firestore:rules
# Deploy Storage rules
firebase deploy --only storage
# Deploy Realtime Database rules
firebase deploy --only database
# Deploy all rules
firebase deploy --only firestore:rules,storage,database
# View deployed rules in Firebase Console
# Firestore: Firebase Console > Firestore > Rules
# Storage: Firebase Console > Storage > Rules
# Realtime DB: Firebase Console > Realtime Database > Rules
Errores de seguridad comunes
Evita estos errores frecuentes:
Nunca hagas esto:
// DANGEROUS: Allows anyone to read/write everything
match /{document=**} {
allow read, write: if true;
}
// DANGEROUS: Only checks authentication, not authorization
match /users/{userId} {
allow read, write: if request.auth != null;
}
Haz esto en su lugar:
// SECURE: Check both authentication AND authorization
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
// SECURE: Validate all incoming data
match /posts/{postId} {
allow create: if request.auth != null
&& request.resource.data.authorId == request.auth.uid
&& request.resource.data.title is string
&& request.resource.data.title.size() > 0;
}
💡 Puntos clave
- • Las reglas de seguridad son la primera línea de defensa contra accesos no autorizados
- • Valida siempre autenticación y autorización
- • Usa funciones para mantener reglas claras y reutilizables
- • Valida estructura y contenido de datos en reglas de escritura
- • Prueba las reglas antes de desplegar en producción
- • Nunca uses allow read, write: if true en producción
📚 Más recursos
-
Resumen de reglas de seguridad →
Guía completa de reglas de seguridad en todos los servicios.
-
Guía de reglas de seguridad de Firestore →
Guía detallada para asegurar tu base de datos Firestore.
-
Guía de reglas de seguridad de Storage →
Asegura tus buckets de Cloud Storage con reglas personalizadas.
-
Pruebas de reglas de seguridad →
Escribe tests unitarios para tus reglas con el emulador.
-
Referencia del lenguaje de reglas →
Referencia completa de la sintaxis de reglas de seguridad.