基于JWT邮箱域名限制React客户端应用访问的安全性疑问
用户能否篡改邮箱信息?
不能直接篡改JWT payload里的邮箱信息。Supabase生成的JWT是经过服务端签名的,一旦用户修改payload中的邮箱(或其他字段),JWT的签名就会失效,Supabase的Auth服务和你的后端会直接拒绝这个无效的JWT。
但要注意:前端获取的session.user.email是从本地存储的JWT解析出来的,如果用户通过开发者工具手动修改本地存储的内容,前端逻辑会误以为邮箱是domain.com的,从而跳转到/admin页面——但这种情况下,用户调用需要管理员权限的后端接口时,因为JWT本身是无效的,会被服务端直接拦截。
你忽略的安全问题
前端路由限制不代表真正的权限控制
你现在的代码只是在前端层面做路由跳转,本质是「隐藏UI」而非阻止访问。如果用户直接在地址栏输入/admin,或者绕过前端路由逻辑,虽然可能看到页面,但调用后端接口时会因权限不足失败;如果/admin页面是纯前端内容,甚至可能直接被用户查看。所有管理员专属的后端接口必须单独做权限校验,不能只依赖前端路由。邮箱域名校验的前置风险
如果你没在Supabase中设置邮箱域名白名单(仅允许domain.com用户注册),或者未开启邮箱验证,攻击者可能注册非法邮箱(若domain.com是开放域名)或用未验证的邮箱登录,绕过前端的域名校验逻辑。XSS攻击风险
本地存储的JWT容易成为XSS攻击的目标。如果应用存在XSS漏洞,攻击者可以窃取用户的JWT(包括管理员的),直接冒用身份访问管理员功能。必须做好XSS防范:比如依赖React的自动转义机制,避免使用dangerouslySetInnerHTML,配置内容安全策略(CSP)等。
优化建议
- 后端权限校验是核心:不管用邮箱域名还是自定义JWT claims,所有管理员专属的接口(包括Supabase数据库查询)都必须在服务端校验权限。比如在Supabase Edge Functions中处理管理员请求时,先验证JWT有效性,再检查邮箱域名或自定义的
is_adminclaim。 - 用自定义JWT claims更可靠:相比解析邮箱域名,在JWT中添加
is_admin这类自定义claim更直观,也能避免邮箱格式变化带来的问题。你可以在Supabase的Auth钩子(如beforeSignIn)中根据邮箱域名自动添加该claim。 - 加固Supabase Auth配置:开启邮箱验证,设置邮箱域名白名单,从源头阻止非法用户注册登录。
内容的提问来源于stack exchange,提问作者Adrian Brenne

