Firebase认证后JWT权限问题:如何防止合法Token越权访问用户数据
首先直接给你明确答案:是的,你必须在每个涉及用户私有数据访问的服务/接口中,验证Token解析出的用户email与目标数据的所属用户email一致——这是堵住你当前权限漏洞的核心手段,也是身份认证(Authentication)之后,授权(Authorization)环节的必要逻辑。
接下来我拆解下为什么要这么做,以及怎么优化你之前的方案,避免“场景过多导致脆弱”的问题:
1. 问题本质:Firebase Auth只做认证,不做授权
Firebase Auth签发的JWT仅能证明“请求者是一个已通过认证的合法用户”,但它不会自动帮你判断这个用户是否有权访问当前请求的资源。你遇到的漏洞,正是因为缺少了“当前用户是否是资源所有者”这一步授权校验——只要有合法Token,就能绕开所有权验证访问任意用户的数据。
所以把Token解析出的email传递到服务层,和请求目标数据的所属用户email做对比,是最直接、最可靠的验证方式。举个具体的例子:
当请求photos/user/{id}时:
- 第一步:用Firebase SDK解析请求头里的JWT,拿到当前用户的
currentUserEmail - 第二步:通过路径中的
{id}查询数据库,获取该ID对应的用户emailtargetUserEmail - 第三步:对比
currentUserEmail和targetUserEmail,只有两者完全一致时,才返回对应的数据;否则返回403 Forbidden
2. 优化自定义授权策略:抽象复用逻辑,避免脆弱性
你之前尝试用自定义授权属性策略,但因为场景多觉得脆弱——核心问题是你可能在每个接口都写了重复的校验逻辑,导致维护成本高、容易遗漏。解决办法是把通用的授权逻辑抽象成可复用的中间件/过滤器,而不是每个接口单独实现:
比如在你的后端框架中(不管是Node.js、Java Spring、Django等),可以编写一个全局或局部的中间件:
- 统一处理JWT解析:调用Firebase Auth的SDK验证Token有效性,并提取当前用户的email
- 统一提取目标用户标识:根据接口的路径规则(比如从
{id}查email,或者如果接口路径直接用email作为参数,比如photos/user/{email},可以直接取路径参数) - 统一做身份匹配校验:对比当前用户email和目标用户email,不一致则直接拦截请求,返回403
这样所有需要用户数据隔离的接口,只需要挂载这个中间件即可,不用重复写校验逻辑,既减少了代码冗余,也避免了遗漏场景的问题,大幅降低脆弱性。
3. 额外的安全加固建议
除了服务层的校验,还可以做这些优化来提升整体安全性:
- 优先用Firebase Auth的
uid作为用户标识:虽然你现在用email,但email存在被修改的可能,而Firebase的uid是用户的永久唯一标识,更适合作为数据库中的用户主键。如果业务允许,可以逐步切换用uid做身份匹配。 - 数据库层面加安全规则兜底:如果你用的是Firebase Firestore或Realtime Database,可以直接在数据库规则中添加所有权校验,比如Firestore规则:
这样即使服务层的校验出现漏洞,数据库层面也能拦截非法访问,形成双重防护。match /photos/{userId}/{photoId} { allow read: if request.auth.token.email == get(/databases/$(database)/documents/users/$(userId)).data.email; } - 避免在请求体中传递用户标识:尽量把用户标识放在URL路径参数中,或者直接从Token中提取,防止恶意篡改(虽然JWT的 payload 是签名不可篡改的,但路径参数的
{id}可能被修改,所以必须校验{id}对应的用户身份)
总结一下:你需要做用户身份与资源所有者的匹配验证,把Token中的email传到服务层是正确的方向,但通过抽象中间件的方式可以避免重复逻辑导致的脆弱性。结合数据库安全规则做兜底,能进一步提升系统的安全性。
内容的提问来源于stack exchange,提问作者ismv

