This document outlines security best practices, production deployment requirements, and security considerations for MessageAI.
- Security Overview
- Development vs Production
- Firebase Security Rules
- User Flow Security Validation
- API Key Security
- User Data Protection
- Production Checklist
- Security Monitoring
- Common Security Issues
MessageAI implements a multi-layered security approach:
- Authentication: Firebase Auth with email/password
- Authorization: Firestore security rules
- Data Protection: User data isolation and access controls
- API Security: Server-side API key management (for AI features)
- Network Security: HTTPS/TLS for all communications
Development Mode: Ultra-permissive rules for rapid development Production Mode: ✅ OPTIMIZED - Comprehensive security validation with user flow analysis
Recent Security Improvements (Latest Update):
- ✅ Fixed Overly Restrictive Rules: Corrected Firestore rules that were preventing core app functionality
- ✅ Operation Separation: Implemented proper read/create/update operation separation
- ✅ Data Reference Correction: Fixed
resource.datavsrequest.resource.datausage - ✅ User Flow Validation: Comprehensive security analysis of all core user flows
- ✅ Edge Case Documentation: Documented security edge cases and handling
- ✅ Performance Analysis: Documented security vs performance trade-offs
Firestore Rules: Ultra-permissive for development
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true; // UNSAFE - Development only
}
}
}API Keys: Exposed in environment variables
- All
EXPO_PUBLIC_variables are visible to clients - Suitable for development and testing only
Authentication: Basic email/password only
- No Google OAuth implementation
- No multi-factor authentication
Firestore Rules: Strict access controls
- User data isolation
- Conversation-based permissions
- Message access restrictions
API Keys: Server-side only
- Never expose API keys to mobile clients
- Use Firebase Cloud Functions for AI features
- Implement proper authentication
Authentication: Enhanced security
- Multi-factor authentication
- Session management
- Account lockout policies
File: firestore.rules.production
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Users can only read/write their own profile
match /users/{userId} {
allow read: if request.auth != null;
allow write: if request.auth != null && request.auth.uid == userId;
}
// Friend requests - users can read their own requests
match /friendRequests/{requestId} {
allow read: if request.auth != null &&
(request.auth.uid == resource.data.fromUserId ||
request.auth.uid == resource.data.toUserId);
allow create: if request.auth != null &&
request.auth.uid == request.resource.data.fromUserId;
allow update: if request.auth != null &&
request.auth.uid == resource.data.toUserId;
}
// Conversations - only participants can access
match /conversations/{conversationId} {
allow read: if request.auth != null &&
request.auth.uid in resource.data.participants;
allow create: if request.auth != null &&
request.auth.uid in request.resource.data.participants;
allow update: if request.auth != null &&
request.auth.uid in resource.data.participants;
}
// Messages - only accessible by conversation participants
match /messages/{messageId} {
allow read: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(resource.data.conversationId)).data.participants;
allow create: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(request.resource.data.conversationId)).data.participants;
allow update: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(resource.data.conversationId)).data.participants;
}
// Typing indicators - only accessible by conversation participants
match /typing/{conversationId} {
allow read: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(conversationId)).data.participants;
allow create: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(conversationId)).data.participants;
allow update: if request.auth != null &&
request.auth.uid in get(/databases/$(database)/documents/conversations/$(conversationId)).data.participants;
}
}
}- User Profiles: Users can only modify their own profiles, but can read any user profile (needed for friend search)
- Friend Requests: Users can only read requests sent to/from them, only sender can create, only recipient can update
- Conversations: Only participants can access conversation data, with proper separation of read/create/update operations
- Messages: Only conversation participants can access messages, with cross-document validation via conversation lookup
- Typing Indicators: Only conversation participants can access typing status, with proper operation separation
Key Security Patterns Implemented:
- Authentication Required: All operations require
request.auth != null - Operation Separation: Separate
read,create, andupdateoperations for fine-grained control - Data Reference Correctness:
- Create operations use
request.resource.data(incoming data) - Read/Update operations use
resource.data(existing data)
- Create operations use
- Cross-Document Validation: Messages and typing indicators validate participation via conversation lookup
- Participant-Based Access: All conversation-related operations validate user participation
Step-by-Step Security Analysis: Enter → Type → Send → Read Receipts
| Step | Operation | Collection | Security Validation | Status |
|---|---|---|---|---|
| 1. Enter | Read conversation | conversations | User in participants | ✅ PERMITTED |
| 2. Start typing | Create typing | typing | User in participants | ✅ PERMITTED |
| 3. Stop typing | Update typing | typing | User in participants | ✅ PERMITTED |
| 4. Send message | Create message | messages | User in participants | ✅ PERMITTED |
| 5. Receive message | Read message | messages | User in participants | ✅ PERMITTED |
| 6. Mark read | Update message | messages | User in participants | ✅ PERMITTED |
| 7. See read receipt | Read message | messages | User in participants | ✅ PERMITTED |
| 8. Real-time updates | Read all | All collections | User in participants | ✅ PERMITTED |
Step-by-Step Security Analysis: Search → Send → Receive → Accept/Decline → Response
| Step | Operation | Collection | Security Validation | Status |
|---|---|---|---|---|
| 1. Search users | Read user profiles | users | Any authenticated user | ✅ PERMITTED |
| 2. Send request | Create friend request | friendRequests | Sender only | ✅ PERMITTED |
| 3. See request | Read friend request | friendRequests | Sender or recipient | ✅ PERMITTED |
| 4. Accept request | Update friend request | friendRequests | Recipient only | ✅ PERMITTED |
| 5. Decline request | Update friend request | friendRequests | Recipient only | ✅ PERMITTED |
| 6. See response | Read friend request | friendRequests | Sender or recipient | ✅ PERMITTED |
| 7. View profiles | Read user profiles | users | Any authenticated user | ✅ PERMITTED |
| 8. Real-time updates | Read friend requests | friendRequests | Sender or recipient | ✅ PERMITTED |
Step-by-Step Security Analysis: Create Direct/Group → Send First Message → Real-time Updates
| Step | Operation | Collection | Security Validation | Status |
|---|---|---|---|---|
| 1. Start direct message | Create conversation | conversations | User in participants | ✅ PERMITTED |
| 2. Start group message | Create conversation | conversations | User in participants | ✅ PERMITTED |
| 3. Others see conversation | Read conversation | conversations | User in participants | ✅ PERMITTED |
| 4. Send first message | Create message | messages | User in participants | ✅ PERMITTED |
| 5. Others receive message | Read message | messages | User in participants | ✅ PERMITTED |
| 6. Real-time updates | Read all | Both collections | User in participants | ✅ PERMITTED |
| 7. Update metadata | Update conversation | conversations | User in participants | ✅ PERMITTED |
Handled Edge Cases:
- User not in participants array: ❌ DENIED - Prevents unauthorized access
- Invalid participant IDs: ✅ PERMITTED - Rules don't validate user existence (performance consideration)
- Empty participants array: ❌ DENIED - Prevents empty conversation creation
- Cross-conversation access: ❌ DENIED - Users can only access conversations they're in
- Unauthorized message creation: ❌ DENIED - Must be conversation participant
Security vs Performance Trade-offs:
- Message Operations: Each message operation triggers conversation lookup (1 write + 1 read)
- Typing Indicators: Similar performance impact as messages
- Real-time Subscriptions: Respect security boundaries but may impact performance
- Future Optimization: Consider denormalizing participant data for high-volume operations
# Copy production rules
cp firestore.rules.production firestore.rules
# Deploy to Firebase
firebase deploy --only firestore:rules
# Verify deployment
firebase firestore:rules:getEnvironment Variables (Development Only):
# These are exposed to the client - NOT SECURE for production
EXPO_PUBLIC_FIREBASE_API_KEY=your-api-key
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
EXPO_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
# ... other Firebase configNever expose API keys in mobile apps. Use these approaches:
- Firebase Cloud Functions for AI features:
// functions/index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin");
exports.processAIRequest = functions.https.onCall(async (data, context) => {
// Verify user authentication
if (!context.auth) {
throw new functions.https.HttpsError(
"unauthenticated",
"User must be authenticated"
);
}
// Process AI request server-side
const openai = new OpenAI({
apiKey: functions.config().openai.key, // Server-side only
});
// Return processed result
return { result: processedData };
});- Firebase App Check for additional security:
// Verify requests are from your app
const appCheckToken = await getAppCheckToken();- Rate Limiting per user:
// Implement rate limiting in Cloud Functions
const rateLimit = require("express-rate-limit");Current Status: Not implemented (planned for Epic 5)
Production Implementation:
- OpenAI API keys stored server-side only
- User authentication required for AI features
- Rate limiting per user (e.g., 100 requests/day)
- Input validation and sanitization
- Response filtering for inappropriate content
- User Profiles: Each user can only access their own profile
- Conversations: Only participants can access conversation data
- Messages: Protected by conversation participation
- Friend Requests: Users can only see their own requests
- Message Content: Only store necessary message data
- User Information: Collect only required profile information
- Logging: Log only essential debugging information
- Analytics: Use Firebase Analytics with privacy controls
- Messages: Retained indefinitely (user choice)
- Logs: 7-day retention with automatic cleanup
- Friend Requests: Retained until accepted/declined
- User Profiles: Retained until account deletion
- User Blocking: Users can block others to prevent contact
- Profile Visibility: Users control their profile information
- Message Deletion: Users can delete their own messages
- Account Deletion: Complete data removal on request
- Firestore Rules: Deploy production security rules
- API Keys: Move all API keys to server-side (Cloud Functions)
- Authentication: Implement proper user authentication
- Input Validation: Validate all user inputs
- Rate Limiting: Implement API rate limiting
- Error Handling: Secure error messages (no sensitive data)
- Logging: Review logs for sensitive information
- Dependencies: Update all dependencies to latest versions
- Environment Variables: Remove all
EXPO_PUBLIC_variables - Firebase App Check: Enable App Check for additional security
- Firebase App Check: Enable and configure
- Firebase Security Rules: Deploy production rules
- Firebase Indexes: Deploy required indexes
- Firebase Monitoring: Set up alerts and monitoring
- Firebase Backup: Configure automated backups
- Firebase Billing: Set up billing alerts
- Code Review: Security-focused code review
- Penetration Testing: Basic security testing
- Dependency Audit: Check for vulnerable dependencies
- SSL/TLS: Ensure all communications use HTTPS
- Session Management: Implement secure session handling
- Error Boundaries: Implement React error boundaries
- Firebase Monitoring: Set up performance monitoring
- Error Tracking: Implement error tracking and alerting
- Security Alerts: Set up security event monitoring
- Usage Monitoring: Monitor API usage and costs
- Performance Monitoring: Track app performance metrics
- Firebase Console: Monitor authentication events
- Firebase Monitoring: Track security-related metrics
- Firebase Alerts: Set up security event alerts
- Firebase Logs: Review security-related logs
- Authentication Events: Monitor sign-in/sign-up patterns
- Failed Requests: Track failed authentication attempts
- Suspicious Activity: Monitor unusual user behavior
- API Usage: Track API usage patterns and anomalies
- Failed authentication attempts
- Unusual API usage patterns
- High error rates
- Unauthorized access attempts
- Data access patterns
Problem: API keys visible in client-side code Solution: Move all API keys to server-side (Cloud Functions)
Problem: Rules allow unrestricted access Solution: Implement strict access controls based on user authentication
Problem: User input not validated Solution: Implement input validation and sanitization
Problem: Weak authentication mechanisms Solution: Implement strong authentication with MFA
Problem: Sensitive data in error messages Solution: Implement secure error handling
Problem: No protection against abuse Solution: Implement rate limiting per user
- Never commit API keys to version control
- Use environment variables for configuration
- Implement proper error handling without data leakage
- Validate all user inputs before processing
- Use HTTPS for all communications
- Keep dependencies updated to latest versions
- Deploy production security rules immediately
- Move all API keys to server-side
- Implement proper authentication and authorization
- Set up monitoring and alerting
- Regular security audits and updates
- User education about security practices
- Regular dependency updates for security patches
- Monitor security advisories for Firebase and dependencies
- Regular security reviews of code and configuration
- User feedback on security concerns
- Penetration testing for critical vulnerabilities
- Firebase Security Rules Documentation
- Firebase App Check Documentation
- Firebase Security Best Practices
- OWASP Mobile Security
- React Native Security
-
Immediate Response:
- Assess the scope of the incident
- Implement emergency security measures
- Notify affected users if necessary
-
Investigation:
- Review logs and monitoring data
- Identify the root cause
- Document the incident
-
Recovery:
- Implement fixes for identified vulnerabilities
- Update security measures
- Test and verify fixes
-
Post-Incident:
- Review and update security procedures
- Conduct security audit
- Update documentation
- Firebase Support: Firebase Console Support
- Security Issues: Report via Firebase Console or GitHub Issues
- Emergency Contact: [Your emergency contact information]
This security documentation provides comprehensive guidance for securing MessageAI in production. Regular review and updates of security measures are essential for maintaining a secure application.