Flutter接入Firebase Auth时仅允许可信上架App通信的实现疑问
核心结论
仅把登录方式限制为Google、手机号登录,根本没法100%保证只有你的官方App能生成有效JWT和后端通信,最多只能挡住最基础的无差别接口爬取,离你要的“校验请求来源是上架的官方版本”的目标差得远。
之前的认知误区拆解
你会觉得Google/手机号登录绑了SHA-1就安全,完全是没搞懂这两个登录流程的底层校验逻辑:
- 大家熟知的“必须注册SHA-1才能用Google/手机号登录”的要求,本质是Google为了优化登录体验做的配套功能,不是什么安全校验锁:比如Android端注册SHA-1,只是为了让系统能自动读取短信验证码、自动唤起已登录的Google账号弹窗,这个校验发生在客户端和Google基础服务的交互环节,根本不是Firebase后端对登录请求的强安全拦截。
- 真实的绕过路径连你的签名校验都碰不到:
- 针对手机号登录:攻击者只要逆向你的APK,把里面写死的Firebase公开配置(项目ID、公开API Key这些,本来就没有保密要求)抄到自己的恶意程序里,哪怕他没注册任何SHA-1,只要能拿到用户收到的短信验证码、手动输入提交,Firebase照样返回合法JWT,根本不会因为他的客户端没绑SHA-1就拦截。
- 针对Google登录:Firebase项目对应的OAuth客户端ID是完全公开的(同样能从APK里逆向拿到),攻击者完全可以用这个公开ID,通过自己搭的web端OAuth流程,在完全脱离你App的环境下拿到合法的Google登录ID Token,再提交给Firebase换取JWT,整个过程根本不需要和你装了SHA-1的官方App有任何交互。
- 最根本的逻辑偏差:Firebase Auth返回的JWT,从设计之初就只负责证明「这个请求对应的合法用户是谁」,从来没承担过「这个请求是从哪个客户端发出来的」的校验责任。不管攻击者用什么登录方式拿到的JWT,结构、签名、有效期和你官方App里生成的完全一致,你的后端拿到根本分不出来来源。
可落地的实操步骤
先把随手可堵的漏洞堵上
- 直接在Firebase控制台关掉邮箱密码、匿名登录这类完全无客户端校验的登录渠道,只留Google、手机号登录,这一步就能挡住90%随便爬接口的恶意调用——毕竟大部分攻击者连你APK里的Firebase配置都提取不到,根本模拟不出合法的登录流程。
- 别浪费时间自己写客户端签名校验、代码混淆来做来源管控,这类逻辑只要被逆向很快就能拆穿,投入产出比极低。
上真正能证明客户端来源的能力
- 直接用Firebase官方的App Check组件解决核心需求,这个组件从设计上就是为了实现“校验请求确实来自我上架的官方App”,和Firebase Auth是完全独立的两个模块:
- Android端配置Play Integrity提供方,把你官方上架版本的包名、Google Play签名的SHA-256值注册进去,这个校验是系统层面做的,会自动判断发起请求的App有没有被篡改、是不是你注册的官方包,根本没法靠简单的客户端逆向绕过。
- iOS端配置DeviceCheck提供方,实现同等级的系统层校验。
- 配置完之后,所有发往你后端、发往Firebase服务的请求,都会自动带上App Check生成的短期令牌,你在服务端接请求时先验这个令牌的合法性,再继续处理业务逻辑就行。
- 要搞清楚预期:Play Integrity的校验不是为了100%防国家级高级攻击者,但是已经是现在移动端能用到的最强的客户端来源校验手段,比靠登录渠道做校验可靠几个数量级。
后端接口做配套优化
- 别只验JWT的签名和有效期,加两层强制校验:
- 校验JWT里的
sign_in_provider字段,只允许google.com、phone两个合法来源,其他渠道生成的JWT直接拒绝访问。 - 强制要求请求携带合法的App Check令牌,只要令牌缺失或者校验不通过,哪怕JWT是完全合法的,也直接拒——从根源上把“用户身份合法”和“请求来自官方App”两个校验独立开,不要混为一谈。
- 校验JWT里的
实操避坑:App Check的令牌是短期动态生成的,不要为了省性能在客户端缓存长期令牌,每次请求带最新的实时令牌就行,官方SDK会自动处理刷新逻辑,不需要自己额外写代码。
内容的提问来源于stack exchange,提问作者Ani
相关产品推荐
相关产品推荐

