Skip to main content

鉴权与安全

在全栈开发中,如何确认“你是谁”(认证 Authentication)以及“你能做什么”(授权 Authorization)是核心问题。同时,防范常见的 Web 攻击也是全栈工程师必须具备的安全意识。

1. 认证机制:Session vs JWT

这是最传统的 Web 认证方式。

  1. 用户登录成功后,服务器在内存或 Redis 中生成一个 sessionId,并将其通过 HTTP Response 的 Set-Cookie 头发送给浏览器。
  2. 浏览器之后每次请求都会自动携带这个 Cookie。
  3. 服务器拿到 Cookie 中的 sessionId,去内存或 Redis 中查找对应的用户信息。
  • 优点:服务器完全掌控登录状态,可以随时强制用户下线。
  • 缺点:难以扩展到多台服务器(需要 Session 共享),且存在 CSRF 风险。

JWT (JSON Web Token) 机制

目前前后端分离架构中最流行的方案,属于无状态认证

  1. 用户登录成功后,服务器生成一个 JWT 字符串(包含 Header, Payload, Signature)返回给前端。
  2. 前端通常将其保存在 localStoragesessionStorage 中。
  3. 之后的每次请求,前端手动将 JWT 放入 HTTP Request 的 Authorization: Bearer <token> 头部中。
  4. 服务器无需查询数据库,只需用约定的密钥验证 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 或进行恶意操作。

防御手段

  1. 永远不信任用户的输入。对所有用户输入的内容进行转义(Escape)和过滤。
  2. 现代前端框架(如 React, Vue)默认会对绑定的数据进行转义,大大降低了 XSS 风险,但使用 v-htmldangerouslySetInnerHTML 时仍需极其小心,必须配合 DOMPurify 等库进行清洗。
  3. 开启 HTTP 响应头:Content-Security-Policy (CSP),限制浏览器只能加载特定来源的资源。

CSRF (Cross-Site Request Forgery) 跨站请求伪造

原理:攻击者诱导用户点击恶意链接,利用用户浏览器中已登录网站的 Cookie 身份,向该网站发送恶意请求(如转账、发帖)。

防御手段

  1. 放弃 Cookie 鉴权:全面改用 JWT 放在 Header 中提交。因为浏览器不会自动携带 Header,天然免疫 CSRF。
  2. 如果必须用 Cookie,设置 SameSite=LaxStrict 属性,阻止第三方网站携带 Cookie。
  3. 引入 CSRF Token 机制,每次请求必须携带一个由服务器生成的随机字符串供校验。

SQL 注入 (SQL Injection)

原理:攻击者在输入框中输入恶意的 SQL 语句片段,如果后端直接拼接 SQL 字符串执行,就会导致数据库被篡改或数据泄露。

防御手段

  1. 坚决抵制字符串拼接 SQL
  2. 使用参数化查询(Parameterized Queries)或预编译语句。
  3. 全面使用 ORM 框架(如 Prisma, TypeORM),它们在底层已经处理好了防止 SQL 注入的问题。

限流防刷 (Rate Limiting)

防止恶意用户利用脚本疯狂调用接口,导致服务器资源耗尽或短信验证码费用爆炸。

防御手段

  1. 在 Nginx 层配置 limit_req 模块。
  2. 在 Node.js 代码中使用 express-rate-limit 等中间件,基于用户 IP 或 User ID 进行请求频率限制。
  3. 核心高频接口(如发送验证码、登录)必须增加图形验证码(滑块验证)机制。