firebase_ui_auth的ForgotPasswordScreen账户存在状态泄露及枚举防护问题
解决Firebase UI Auth的账户状态泄露问题
问题现状
- 密码重置流程:输入格式有效但系统不存在的邮箱时,前端直接显示
EMAIL_NOT_FOUND提示,后端API返回明确的账户不存在错误(请求示例及响应如下) - 重复注册流程:即使开启Email Enumeration protection,注册已存在的邮箱时仍会泄露账户已存在的状态
密码重置请求示例
curl "https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=AgwiSyC-tRO9CaBdWeRMU_a1234567-Jl1234ec" \ -H "authority: identitytoolkit.googleapis.com" \ -H "accept: */*" \ -H "accept-language: en-US,en;q=0.9" \ -H "content-type: application/json" \ -H "origin: http://localhost:63865" \ -H "sec-ch-ua: \"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"" \ -H "sec-ch-ua-mobile: ?0" \ -H "sec-ch-ua-platform: \"Windows\"" \ -H "sec-fetch-dest: empty" \ -H "sec-fetch-mode: cors" \ -H "sec-fetch-site: cross-site" \ -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" \ -H "x-client-data: CInaygE=" \ -H "x-client-version: Chrome/JsCore/9.15.0/FirebaseCore-web" \ -H "x-firebase-gmpid: 1:621401234567:web:7d6e685agh2315aea7f93b" \ --data-raw "{\"requestType\":\"PASSWORD_RESET\",\"email\":\"example1@example.com\"}" \ --compressed
对应错误响应
{
"error": {
"code": 400,
"message": "EMAIL_NOT_FOUND",
"errors": [
{
"message": "EMAIL_NOT_FOUND",
"domain": "global",
"reason": "invalid"
}
]
}
}
解决方案
1. 密码重置流程:统一错误提示
Firebase UI Auth默认会直接暴露API错误,需自定义错误拦截逻辑,无论邮箱是否存在,返回通用提示:
const uiConfig = { signInOptions: [firebase.auth.EmailAuthProvider.PROVIDER_ID], callbacks: { signInFailure: (error) => { // 拦截邮箱不存在错误 if (error.code === 'auth/email-not-found') { document.getElementById('auth-error').textContent = '如果该邮箱已注册,重置邮件已发送至对应邮箱'; return false; // 阻止UI显示默认错误 } // 其他错误正常抛出 return true; } }, // 其他UI配置项 }; // 初始化Firebase UI const ui = new firebaseui.auth.AuthUI(firebase.auth()); ui.start('#firebaseui-auth-container', uiConfig);
2. 重复注册流程:自定义注册逻辑
通过Firebase Cloud Functions拦截注册请求,统一返回相同提示,避免泄露账户状态:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.customSignUp = functions.https.onCall(async (data) => { const { email, password } = data; try { // 尝试创建用户 await admin.auth().createUser({ email, password, emailVerified: false }); return { message: '注册请求已处理,请检查邮箱完成验证' }; } catch (error) { // 拦截邮箱已存在错误,返回通用提示 if (error.code === 'auth/email-already-exists') { return { message: '注册请求已处理,请检查邮箱完成验证' }; } // 其他错误抛出通用异常 throw new functions.https.HttpsError('internal', '注册失败,请稍后重试'); } });
3. 启用官方枚举防护
在Firebase控制台Authentication > 设置 > 高级中开启Email Enumeration protection,该功能会自动在登录场景隐藏邮箱不存在的错误,配合上述自定义逻辑覆盖全场景漏洞。
内容的提问来源于stack exchange,提问作者puzzled
相关产品推荐
相关产品推荐

