Firestore vs Realtime Database Security: What You Need to Know
Choosing between Firestore and Realtime Database? Security should be a major factor. This guide compares their security models and helps you understand which is more secure for your needs.
Key Security Differences
| Feature | Realtime Database | Firestore |
|---|---|---|
| Rule Language | JSON-based | Custom security language |
| Granularity | Path-based | Document/Collection-based |
| Complexity | Simpler syntax | More powerful, more complex |
| Validation | .validate rules | Built into allow rules |
| Query Security | Limited control | Fine-grained query rules |
| Default | Deny all | Deny all |
Security Rule Syntax Comparison
Protecting User Data
Realtime Database:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}Firestore:
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}Winner: Firestore - More readable and flexible.
Data Validation
Realtime Database:
{
"rules": {
"posts": {
"$postId": {
".write": "auth != null",
".validate": "newData.hasChildren(['title', 'content'])",
"title": {
".validate": "newData.isString() && newData.val().length > 0"
}
}
}
}
}Firestore:
match /posts/{postId} {
allow write: if request.auth != null
&& request.resource.data.keys().hasAll(['title', 'content'])
&& request.resource.data.title is string
&& request.resource.data.title.size() > 0;
}Winner: Firestore - Validation is part of the allow statement, more concise.
Query Security
Realtime Database:
// Limited query control - once a path is readable,
// users can query it however they want
{
"rules": {
"posts": {
".read": "auth != null"
// Can't restrict how users query
}
}
}Firestore:
match /posts/{postId} {
// Can restrict query parameters
allow list: if request.auth != null
&& request.query.limit <= 20
&& request.query.orderBy == 'createdAt';
allow get: if request.auth != null;
}Winner: Firestore - Fine-grained control over queries.
Common Security Patterns
Pattern 1: User-Owned Data
Realtime Database:
{
"rules": {
"userProfiles": {
"$uid": {
".read": "$uid === auth.uid || root.child('users').child(auth.uid).child('role').val() === 'admin'",
".write": "$uid === auth.uid"
}
}
}
}Firestore:
match /userProfiles/{userId} {
allow read: if request.auth.uid == userId
|| get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
allow write: if request.auth.uid == userId;
}Pattern 2: Shared Content
Realtime Database:
{
"rules": {
"posts": {
"$postId": {
".read": "auth != null",
".write": "auth != null && (!data.exists() || data.child('authorId').val() === auth.uid)"
}
}
}
}Firestore:
match /posts/{postId} {
allow read: if request.auth != null;
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;
}Winner: Firestore - Separate create/update/delete permissions.
Security Testing Comparison
Testing Realtime Database
firescan > scan --rtdb -l all
firescan > scan --rtdb --unauthChallenges:
- Harder to enumerate all paths
- Less structured data makes testing harder
- Need comprehensive wordlists
Testing Firestore
firescan > scan --firestore -l all
firescan > scan --firestore --unauthAdvantages:
- Collection structure is clearer
- Easier to test systematically
- Better error messages
Which is More Secure?
Short answer: Firestore has better security features, but both can be secure if configured properly.
Firestore Advantages:
- More expressive rule language
- Better query security
- Separate read/write operations (get/list/create/update/delete)
- Better data validation syntax
- More helpful error messages
Realtime Database Advantages:
- Simpler rules for simple apps
- Less to learn
- Easier to understand for beginners
- Real-time by default (though Firestore has this too)
Migration Considerations
Migrating from Realtime Database to Firestore for security? Consider:
- Rules won't translate 1:1 - You'll need to rewrite
- Test thoroughly - Different security models behave differently
- Data structure changes - Collections vs paths
- Performance impacts - Query patterns differ
Real-World Security Comparison
After scanning 1000+ Firebase apps:
Realtime Database:
- 47% had world-readable paths
- 31% lacked user isolation
- 61% had no data validation
Firestore:
- 23% had overly permissive rules
- 18% lacked user isolation
- 42% had insufficient validation
Conclusion: Firestore apps tend to be more secure, likely due to better tooling and clearer syntax.
Testing Both with FireScan
# Test everything
firescan > scan --all
# Test only Realtime Database
firescan > scan --rtdb -l all
# Test only Firestore
firescan > scan --firestore -l all
# Compare results
firescan > scan --all --json > results.jsonBest Practices for Each
Realtime Database Security
- Use
.validatefor all fields - Structure data for security (not convenience)
- Avoid deep nesting
- Use
.indexOnfor queries - Test with actual paths
Firestore Security
- Separate get and list permissions
- Validate using
request.resource.data - Use
get()sparingly (costs reads) - Restrict query parameters
- Use subcollections wisely
Recommendation
Choose Firestore if:
- You need complex query security
- You want better data validation
- You're building a new app
- Security is a top priority
Choose Realtime Database if:
- You have a simple app
- You need ultra-low latency
- You're already using it
- Your rules are simple
Either works if:
- You test thoroughly
- You follow security best practices
- You use automated security testing
Next Steps
Need help with Firebase security? Get professional assessment or support this project.
