前端转全栈 09:安全实战——XSS / CSRF / 注入 / 越权 / 密钥

前端全栈tutorial安全xsscsrf注入越权密钥

系列目录:本文是「前端转全栈:Next.js + Supabase 实战」系列的第 9 篇。功能做出来只是 1%,安全守不住就是 0 分。这一篇是前端转全栈的「保命指南」。


前端同学常以为「安全是后端的事」,但当你自己写全栈,安全就是你的事。下面五个坑,每一个都曾让真实公司上新闻。


一、XSS:把用户输入当 HTML 渲染

原理:用户提交 <script>偷cookie</script>,你却直接插进页面,脚本就在别的用户浏览器里执行。

// ❌ 危险:直接插入用户内容
<div dangerouslySetInnerHTML={{ __html: userContent }} />

防御

  • React 默认对所有插值做转义({userContent} 是安全的),别用 dangerouslySetInnerHTML
  • 必须渲染富文本时,用 DOMPurify 等库过滤白名单标签。
  • Content-Security-Policy 响应头,限制脚本来源。

二、CSRF:借你的登录态干坏事

原理:你登录了银行,攻击者诱导你点一个链接,悄悄发起「转账」请求——浏览器自动带上你的 cookie,服务端以为是本人操作。

防御(本站场景)

  • Supabase Auth 用的是 SameSite cookie + 短时效 token,天然抗 CSRF。SameSite 限制第三方站点带 cookie。
  • 若自己写 session,设置 SameSite=Lax/Strict,关键操作加 CSRF token。
  • 对「状态改变」的请求(POST/PUT/DELETE)严格校验来源 Origin / Referer 头。

三、SQL 注入:拼接出来的灾难

原理:把用户输入直接拼进 SQL 字符串。

// ❌ 致命:用户输入拼进查询
const sql = `SELECT * FROM users WHERE name = '${req.body.name}'`

如果用户传 name = ' OR '1'='1,整张表就泄露了。

防御(用参数化 / ORM)

// ✅ Supabase 查询自动参数化,不会注入
supabase.from("users").select("*").eq("name", req.body.name)

只要永远用参数化查询或 ORM(Prisma/Drizzle),绝不字符串拼接 SQL,注入就基本无解。本站全程 Supabase 查询,天然安全。


四、越权访问(Broken Access Control)

原理:用户 A 把自己的请求 id=123 改成 id=456,就能看/删用户 B 的数据。

防御

  • 对象级鉴权:每个写操作都验证「这条记录属于当前用户」。
const { data } = await supabase.from("comments").delete()
  .eq("id", id).eq("user_id", user.id) // 双重条件锁死归属
  • 配合 RLS(第 7 篇):USING (auth.uid() = user_id),即使绕过接口也删不了别人的。
  • 最小权限原则:admin 客户端的 service_role key 只用于真正需要的运维操作,不在普通业务流里用。

五、密钥泄露:最蠢也最常见

原理:把 SUPABASE_SERVICE_ROLE_KEY、数据库密码写进前端代码或提交到 GitHub 公开仓库,等于把家门钥匙挂门口。

防御清单

  • 所有密钥进环境变量(.env.local),永不进前端、永不提交
  • 前端只能有 NEXT_PUBLIC_ 开头的公开 key(anon key 本就设计为公开)。
  • .gitignore 屏蔽 .env*;用 git-secrets / GitHub 推送保护防止误提交。
  • 泄露即轮换(rotate),别抱侥幸心理。

六、全栈安全自查清单

部署前逐条过:

  • [ ] 所有输出做了 HTML 转义(没用 dangerouslySetInnerHTML 或已净化)
  • [ ] 所有 DB 查询参数化 / 走 ORM
  • [ ] 每个写操作验证资源归属(对象级鉴权)
  • [ ] RLS / 行级权限已开启
  • [ ] 密钥全在环境变量,无硬编码、无提交
  • [ ] 错误响应不泄露堆栈 / 内部路径
  • [ ] 设置了 CSP、SameSite cookie 等基础防护头

总结

  • XSS:别直接渲染用户输入,React 默认转义是朋友。
  • CSRF:SameSite cookie + 校验来源。
  • SQL 注入:参数化查询 / ORM,杜绝字符串拼接。
  • 越权:对象级鉴权 + RLS 双保险。
  • 密钥:环境变量 + 不提交 + 泄露即轮换。

安全不是功能,是底线。下一篇我们补上「通用 Node 后端」——当你需要 Next.js 之外的独立服务时怎么办。


练习:打开你项目里所有用到 dangerouslySetInnerHTML 或字符串拼接 SQL 的地方,逐一改成安全写法;再检查 .env.local 是否已被 .gitignore 屏蔽。

Comments

Sign in to leave a comment.