鉴权与安全
在全栈开发中,如何确认“你是谁”(认证 Authentication)以及“你能做什么”(授权 Authorization)是核心问题。同时,防范常见的 Web 攻击也是全栈工程师必须具备的安全意识。
1. 认证机制:Session vs JWT
Cookie & Session 机制
这是最传统的 Web 认证方式。
- 用户登录成功后,服务器在内存或 Redis 中生成一个 sessionId,并将其通过 HTTP Response 的
Set-Cookie头发送给浏览器。 - 浏览器之后每次请求都会自动携带这个 Cookie。
- 服务器拿到 Cookie 中的 sessionId,去内存或 Redis 中查找对应的用户信息。
- 优点:服务器完全掌控登录状态,可以随时强制用户下线。
- 缺点:难以扩展到多台服务器(需要 Session 共享),且存在 CSRF 风险。
JWT (JSON Web Token) 机制
目前前后端分离架构中最流行的方案,属于无状态认证。
- 用户登录成功后,服务器生成一个 JWT 字符串(包含 Header, Payload, Signature)返回给前端。
- 前端通常将其保存在
localStorage或sessionStorage中。 - 之后的每次请求,前端手动将 JWT 放入 HTTP Request 的
Authorization: Bearer <token>头部中。 - 服务器无需查询数据库,只需用约定的密钥验证 JWT 的签名是否合法即可确认用户身份。
- 优点:无状态,天然支持分布式和微服务;不受跨域限制;防止 CSRF 攻击。
- 缺点:Token 一旦签发,在过期前无法轻易作废(除非配合 Redis 做黑名单校验)。
最佳实践:通常采用双 Token 机制。一个短效的
access_token用于日常请求,一个长效的refresh_token用于当 access_token 过期时无感刷新,提升安全性。
2. 授权与权限控制 (RBAC)
RBAC (Role-Based Access Control) 即基于角色的访问控制,是最常用的权限模型。
核心三要素:
- User (用户):系统的使用者。
- Role (角色):如“管理员”、“普通用户”、“财务”。
- Permission (权限):如“删除文章”、“查看报表”。
逻辑关系:给用户分配角色,给角色分配权限。代码中只需判断用户拥有的角色是否包含某个权限。
3. 常见 Web 安全防御
XSS (Cross-Site Scripting) 跨站脚本攻击
原理:攻击者在页面中注入恶意的 JavaScript 代码,当其他用户浏览该页面时,代码在用户的浏览器中执行,从而窃取 Cookie、Token 或进行恶意操作。
防御手段:
- 永远不信任用户的输入。对所有用户输入的内容进行转义(Escape)和过滤。
- 现代前端框架(如 React, Vue)默认会对绑定的数据进行转义,大大降低了 XSS 风险,但使用
v-html或dangerouslySetInnerHTML时仍需极其小心,必须配合 DOMPurify 等库进行清洗。 - 开启 HTTP 响应头:
Content-Security-Policy(CSP),限制浏览器只能加载特定来源的资源。
CSRF (Cross-Site Request Forgery) 跨站请求伪造
原理:攻击者诱导用户点击恶意链接,利用用户浏览器中已登录网站的 Cookie 身份,向该网站发送恶意请求(如转账、发帖)。
防御手段:
- 放弃 Cookie 鉴权:全面改用 JWT 放在 Header 中提交。因为浏览器不会自动携带 Header,天然免疫 CSRF。
- 如果必须用 Cookie,设置
SameSite=Lax或Strict属性,阻止第三方网站携带 Cookie。 - 引入 CSRF Token 机制,每次请求必须携带一个由服务器生成的随机字符串供校验。
SQL 注入 (SQL Injection)
原理:攻击者在输入框中输入恶意的 SQL 语句片段,如果后端直接拼接 SQL 字符串执行,就会导致数据库被篡改或数据泄露。
防御手段:
- 坚决抵制字符串拼接 SQL。
- 使用参数化查询(Parameterized Queries)或预编译语句。
- 全面使用 ORM 框架(如 Prisma, TypeORM),它们在底层已经处理好了防止 SQL 注入的问题。
限流防刷 (Rate Limiting)
防止恶意用户利用脚本疯狂调用接口,导致服务器资源耗尽或短信验证码费用爆炸。
防御手段:
- 在 Nginx 层配置
limit_req模块。 - 在 Node.js 代码中使用
express-rate-limit等中间件,基于用户 IP 或 User ID 进行请求频率限制。 - 核心高频接口(如发送验证码、登录)必须增加图形验证码(滑块验证)机制。