Firebase Authentication: Weak Password Complexity Policy¶
Name: Weak Password Complexity Policy
Applicable Services: Firebase Authentication
Description¶
Password Security Risk
The Configuration Flaw: Firebase Authentication password policy is configured with insufficient complexity requirements, allowing users to create weak passwords that are vulnerable to attack.
Intended Behavior: Password policies should enforce strong complexity requirements including minimum length, character diversity, and prohibition of common passwords to prevent automated attacks.
The Risk: Weak passwords significantly increase the likelihood of successful brute force attacks, credential stuffing, and account takeover attempts.
Impact¶
Account Security Consequences
Weak password policies can lead to serious security breaches:
- Account Compromise: Users with weak passwords are vulnerable to brute force and dictionary attacks
- Credential Stuffing: Attackers can use known weak passwords from other breaches
- Mass Account Takeover: Weak passwords enable large-scale automated attacks
- Data Exposure: Compromised accounts can lead to unauthorized access to sensitive user data
- Reputational Damage: Security breaches erode user trust and damage brand reputation
- Compliance Violations: Weak password policies may violate regulatory requirements
Example Attack Scenarios¶
Exploit Scenario: Automated Brute Force Attack
The Vulnerable Configuration: Firebase Auth configured with minimal password requirements:
// Weak password policy example
const passwordPolicy = {
minLength: 6, // Too short
requireUppercase: false,
requireLowercase: false,
requireNumbers: false,
requireSymbols: false,
prohibitCommonPasswords: false
};
Attack Steps: 1. Attacker identifies user email addresses through reconnaissance 2. Uses automated tools to attempt login with common weak passwords 3. Successfully compromises accounts using passwords like "123456", "password", "qwerty" 4. Gains access to user data and potentially escalates privileges
Common Weak Passwords Targeted: - 123456, password, 123456789 - qwerty, abc123, Password1 - admin, user, guest - Company name variations - Sequential patterns (111111, aaaaaa)
Exploit Scenario: Credential Stuffing Campaign
The Attack: 1. Attacker obtains leaked password databases from other breaches 2. Filters for weak passwords that would pass Firebase's minimal requirements 3. Attempts these credentials against the target application 4. Successfully accesses accounts where users reused weak passwords 5. Harvests personal information and performs unauthorized actions
Detection¶
Check Current Password Policy¶
Firebase Console¶
- Go to Firebase Console → Authentication → Settings → User actions
- Review the "Password policy" section
- Check the configured requirements:
- Minimum length
- Character requirements (uppercase, lowercase, numbers, symbols)
- Common password blocking
Using Firebase Admin SDK¶
const admin = require('firebase-admin');
async function checkPasswordPolicy() {
try {
const projectConfig = await admin.auth().getProjectConfig();
const passwordPolicy = projectConfig.passwordPolicyConfig;
console.log('Current Password Policy:');
console.log('- Minimum Length:', passwordPolicy?.minLength || 'Not set');
console.log('- Require Uppercase:', passwordPolicy?.requireUppercase || false);
console.log('- Require Lowercase:', passwordPolicy?.requireLowercase || false);
console.log('- Require Numbers:', passwordPolicy?.requireNumbers || false);
console.log('- Require Symbols:', passwordPolicy?.requireSymbols || false);
console.log('- Block Common Passwords:', passwordPolicy?.forceUpgradeOnSignin || false);
return passwordPolicy;
} catch (error) {
console.error('Error checking password policy:', error);
}
}
Using gcloud CLI¶
# Get authentication configuration
gcloud identity toolkit config describe --format="value(passwordPolicyConfig)"
# Check specific password policy settings
gcloud identity toolkit config describe \
--format="table(passwordPolicyConfig.minLength:label='Min Length',
passwordPolicyConfig.requireUppercase:label='Uppercase',
passwordPolicyConfig.requireNumbers:label='Numbers')"
Audit Existing User Passwords¶
// Analyze password patterns (be careful with user privacy)
async function auditPasswordStrength() {
console.log('Note: This analysis should be done carefully with user privacy in mind');
// Check for users who might be using weak passwords
// by analyzing login failure patterns and password reset requests
const recentFailures = await admin.firestore()
.collection('auth_logs')
.where('event', '==', 'failed_login')
.where('timestamp', '>', admin.firestore.Timestamp.fromMillis(Date.now() - 86400000)) // 24 hours
.get();
const failuresByUser = {};
recentFailures.forEach(doc => {
const data = doc.data();
failuresByUser[data.email] = (failuresByUser[data.email] || 0) + 1;
});
// Users with many failed attempts might be targets of brute force
const potentialTargets = Object.entries(failuresByUser)
.filter(([email, count]) => count > 10)
.map(([email]) => email);
console.log(`Users with high failed login attempts: ${potentialTargets.length}`);
return {
totalFailures: recentFailures.size,
uniqueTargets: Object.keys(failuresByUser).length,
highRiskUsers: potentialTargets.length
};
}
Remediation¶
Step 1: Configure Strong Password Policy¶
Firebase Console Configuration¶
- Go to Firebase Console → Authentication → Settings
- Scroll to "User actions" section
- Configure "Password policy":
- Minimum length: 12 characters (recommended)
- Require uppercase letters: Enabled
- Require lowercase letters: Enabled
- Require numbers: Enabled
- Require symbols: Enabled
- Block common passwords: Enabled
Using Firebase Admin SDK¶
async function updatePasswordPolicy() {
try {
await admin.auth().updateProjectConfig({
passwordPolicyConfig: {
minLength: 12,
maxLength: 128,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSymbols: true,
forceUpgradeOnSignin: true, // Force existing users to upgrade
allowedNonAlphanumericCharacters: ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '{', '}', '[', ']', '|', '\\', ':', ';', '"', "'", '<', '>', ',', '.', '?', '/']
}
});
console.log('Password policy updated successfully');
} catch (error) {
console.error('Error updating password policy:', error);
}
}
Using gcloud CLI¶
# Update password policy
gcloud identity toolkit config update \
--password-policy-min-length=12 \
--password-policy-require-uppercase \
--password-policy-require-lowercase \
--password-policy-require-numbers \
--password-policy-require-symbols \
--password-policy-force-upgrade-on-signin
Step 2: Implement Client-Side Validation¶
// Client-side password strength validation
function validatePasswordStrength(password) {
const minLength = 12;
const requirements = {
length: password.length >= minLength,
uppercase: /[A-Z]/.test(password),
lowercase: /[a-z]/.test(password),
numbers: /[0-9]/.test(password),
symbols: /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password),
notCommon: !isCommonPassword(password)
};
const strength = Object.values(requirements).filter(Boolean).length;
const isValid = Object.values(requirements).every(Boolean);
return {
isValid,
strength: strength / Object.keys(requirements).length,
requirements,
suggestions: generatePasswordSuggestions(requirements)
};
}
function isCommonPassword(password) {
const commonPasswords = [
'123456', 'password', '123456789', 'qwerty', 'abc123',
'Password1', 'password123', '12345678', 'admin', 'letmein',
'welcome', '123123', 'Password', 'password1', '1234567'
];
return commonPasswords.includes(password.toLowerCase());
}
function generatePasswordSuggestions(requirements) {
const suggestions = [];
if (!requirements.length) {
suggestions.push('Use at least 12 characters');
}
if (!requirements.uppercase) {
suggestions.push('Add uppercase letters (A-Z)');
}
if (!requirements.lowercase) {
suggestions.push('Add lowercase letters (a-z)');
}
if (!requirements.numbers) {
suggestions.push('Add numbers (0-9)');
}
if (!requirements.symbols) {
suggestions.push('Add special characters (!@#$%^&*)');
}
if (!requirements.notCommon) {
suggestions.push('Avoid common passwords');
}
return suggestions;
}
// Real-time password strength indicator
function updatePasswordStrengthIndicator(password) {
const result = validatePasswordStrength(password);
const strengthIndicator = document.getElementById('password-strength');
const suggestionsList = document.getElementById('password-suggestions');
// Update strength indicator
strengthIndicator.className = `strength-${Math.floor(result.strength * 4)}`;
strengthIndicator.textContent = getStrengthLabel(result.strength);
// Update suggestions
suggestionsList.innerHTML = result.suggestions
.map(suggestion => `<li>${suggestion}</li>`)
.join('');
return result.isValid;
}
function getStrengthLabel(strength) {
if (strength < 0.3) return 'Very Weak';
if (strength < 0.5) return 'Weak';
if (strength < 0.7) return 'Fair';
if (strength < 0.9) return 'Good';
return 'Strong';
}
Step 3: User Education and Migration¶
Password Upgrade Campaign¶
// Notify users to upgrade weak passwords
exports.notifyPasswordUpgrade = functions.auth.user().onWrite(async (change, context) => {
const user = change.after?.data();
if (user && !user.passwordUpgraded) {
// Send email notification about new password requirements
await sendPasswordUpgradeNotification(user.email);
// Track upgrade campaign
await admin.firestore()
.collection('password_upgrade_campaign')
.doc(user.uid)
.set({
notified: true,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
email: user.email
});
}
});
async function sendPasswordUpgradeNotification(email) {
const emailTemplate = {
to: email,
subject: 'Important: Update Your Password',
html: `
<h2>Enhanced Security: Password Update Required</h2>
<p>We've enhanced our security requirements. Please update your password to meet our new standards:</p>
<ul>
<li>At least 12 characters long</li>
<li>Contains uppercase and lowercase letters</li>
<li>Includes numbers and special characters</li>
<li>Avoids common password patterns</li>
</ul>
<a href="${process.env.APP_URL}/update-password" style="background: #007bff; color: white; padding: 10px 20px; text-decoration: none;">Update Password</a>
`
};
// Send via your email service
await sendEmail(emailTemplate);
}
Gradual Enforcement¶
// Implement gradual password policy enforcement
async function enforcePasswordPolicy(user, currentPassword) {
const passwordPolicy = await getPasswordPolicy();
const validation = validatePasswordStrength(currentPassword);
if (!validation.isValid) {
// For existing users, provide grace period
const userRecord = await admin.auth().getUser(user.uid);
const accountAge = Date.now() - new Date(userRecord.metadata.creationTime).getTime();
const gracePeriod = 30 * 24 * 60 * 60 * 1000; // 30 days
if (accountAge > gracePeriod) {
// Force password update for older accounts
throw new functions.https.HttpsError(
'failed-precondition',
'Password does not meet security requirements. Please update your password.',
{ suggestions: validation.suggestions }
);
} else {
// Warn new accounts but allow access
console.warn(`User ${user.uid} has weak password, grace period active`);
}
}
return validation.isValid;
}
Step 4: Monitor and Audit¶
// Monitor password policy compliance
exports.monitorPasswordSecurity = functions.firestore
.document('auth_events/{eventId}')
.onCreate(async (snap, context) => {
const event = snap.data();
if (event.type === 'password_change') {
await auditPasswordChange(event);
} else if (event.type === 'failed_login') {
await checkBruteForceAttempt(event);
}
});
async function auditPasswordChange(event) {
// Log password security events
await admin.firestore()
.collection('security_audit')
.add({
type: 'password_policy_compliance',
userId: event.userId,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
meetsPolicy: event.passwordStrength?.isValid || false,
strength: event.passwordStrength?.strength || 0
});
}
async function checkBruteForceAttempt(event) {
const recentAttempts = await admin.firestore()
.collection('auth_events')
.where('type', '==', 'failed_login')
.where('email', '==', event.email)
.where('timestamp', '>', admin.firestore.Timestamp.fromMillis(Date.now() - 900000)) // 15 minutes
.get();
if (recentAttempts.size > 5) {
// Potential brute force attack
await alertSecurityTeam({
type: 'brute_force_attempt',
email: event.email,
attemptCount: recentAttempts.size,
timestamp: new Date().toISOString()
});
}
}
Prevention Best Practices¶
Password Policy Configuration¶
- Minimum Length: At least 12 characters (16+ recommended)
- Character Diversity: Require uppercase, lowercase, numbers, and symbols
- Common Password Blocking: Prevent use of known weak passwords
- Regular Updates: Review and update policy based on threat landscape
User Experience Considerations¶
- Clear Requirements: Display password requirements prominently
- Real-time Feedback: Provide immediate validation feedback
- Strength Indicators: Visual indicators for password strength
- Education: Explain why strong passwords matter
Implementation Guidelines¶
- Gradual Rollout: Implement policy changes gradually to minimize user friction
- Grace Periods: Allow existing users time to update passwords
- Recovery Options: Ensure secure password recovery mechanisms
- Monitoring: Track compliance and security incidents