Firebase账号合并安全漏洞:如何删除邮箱/密码登录方式?
解决方案
1. 通过登录前置触发器阻止未验证账号合并
使用Firebase Cloud Functions的beforeSignIn触发器,当用户尝试用Google登录时,先检查是否已有相同邮箱的未验证账号存在。如果有,直接阻止登录并提示用户处理未验证账号。
示例代码:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.blockUnverifiedAccountMerge = functions.auth.user().beforeSignIn(async (user, context) => { // 仅处理Google登录场景 if (context.provider !== "google.com") return; try { const existingUser = await admin.auth().getUserByEmail(user.email); // 若存在未验证的同邮箱账号,阻止登录 if (!existingUser.emailVerified) { throw new functions.auth.HttpsError( "permission-denied", "该邮箱已存在未验证账号,请先完成邮箱验证或重置密码后再登录" ); } } catch (err) { // 无对应账号,允许正常登录 if (err.code !== "auth/user-not-found") throw err; } });
2. 账号链接时强制验证原账号状态
利用onAccountLink触发器,在两个账号合并前检查原邮箱/密码账号的验证状态。如果原账号未验证,撤销合并操作并提示用户先完成验证。
示例代码:
exports.enforceVerificationBeforeLink = functions.auth.user().onAccountLink(async (user, context) => { // 检查合并前的原账号是否未验证 if (!context.previousUser.emailVerified) { // 撤销账号链接 await admin.auth().unlinkUser(user.uid, context.providerId); throw new functions.auth.HttpsError( "failed-precondition", "请先验证邮箱后再绑定Google账号" ); } });
3. 自定义验证状态替代原生字段
不要依赖Firebase Auth的emailVerified字段控制应用权限,而是在自己的数据库中维护独立的验证状态:
- 用户创建邮箱/密码账号后,数据库中标记
isAppVerified: false - 用户完成邮箱验证流程后,再将
isAppVerified设为true - 应用所有权限逻辑均以自定义的
isAppVerified为准,不受Firebase原生字段变化影响
4. 用安全规则限制未验证账号操作
在Firebase数据库/存储的安全规则中,直接限制未验证账号的访问权限,即使账号合并后也无法获取核心功能权限:
{ "rules": { ".read": "auth != null && auth.token.email_verified == true", ".write": "auth != null && auth.token.email_verified == true" } }
注意:该规则需配合前面的触发器使用,仅靠规则无法阻止恶意登录。
关于禁用单个用户邮箱/密码登录的说明
Firebase Auth不支持直接禁用单个用户的邮箱/密码登录方式,也不允许将密码设为null。设置随机UUID作为密码的方法不仅不规范,还会导致错误提示混淆,严重影响用户体验,不建议采用。
内容的提问来源于stack exchange,提问作者GMoney
相关产品推荐
相关产品推荐

