token存储方案
存储方式(前端)
存储位置 | 优点 | 缺点 |
---|---|---|
Cookie | 可自动随请求发送 | 易被 CSRF 攻击(需设置 SameSite) |
LocalStorage | 不随请求发送,需手动附加 | 易被 XSS 攻击 |
推荐:使用 HttpOnly Cookie 存储 Token,防止 XSS,并设置
SameSite=Strict
防止 CSRF。
什么是CSRF?
CSRF,全称是 Cross-Site Request Forgery(跨站请求伪造),是一种常见的 Web 安全攻击方式。它的本质是:攻击者诱导已登录某网站的用户,在不知情的情况下,向该网站发送恶意请求,从而执行非用户本意的操作。
CSRF 的攻击原理
CSRF 利用了浏览器的“自动携带身份凭证”机制(如 Cookie、Session)。攻击者构造一个请求链接或表单,诱导用户点击或自动触发。由于用户已登录目标网站,浏览器会自动附带身份信息,导致服务器误以为这是用户的真实操作。
例如:
<img src="https://bank.com/transfer?to=hacker&amount=10000">
如果你已登录银行网站并访问了这个页面,浏览器会自动携带 Cookie 发起请求,银行服务器就可能真的执行转账操作。
攻击条件
要成功发起 CSRF 攻击,通常需要满足以下条件:
用户已登录目标网站,并保持登录状态
攻击者能诱导用户访问恶意页面
目标网站对请求来源验证不严(如未使用 CSRF Token)
CSRF 的危害
伪造转账、支付请求
修改用户资料(邮箱、密码)
发布恶意内容(评论、帖子)
删除数据或执行敏感操作
如何防御 CSRF
使用 CSRF Token
每次请求附带一个随机生成的令牌,服务器验证令牌是否有效
验证 Referer 或 Origin
检查请求来源是否来自合法域名
设置 SameSite Cookie 属性
限制第三方网站携带 Cookie 发起请求
重要操作使用验证码或双重确认
增加用户交互,防止自动提交
CSRF 和 XSS 是 Web 安全领域的两大经典漏洞,一个是“伪装你”,一个是“控制你”。
什么是XSS?
XSS,全称是 Cross-Site Scripting(跨站脚本攻击),是一种非常常见的 Web 安全漏洞。它的核心是:攻击者在网页中注入恶意脚本代码(通常是 JavaScript),让用户的浏览器执行这些代码,从而达到窃取信息、控制页面等目的。
XSS 的原理
当网站对用户输入的数据没有进行充分的过滤或转义,攻击者就可以把恶意脚本嵌入到页面中。用户访问这个页面时,浏览器会误以为这些脚本是网站正常内容的一部分,于是就执行了它们。
XSS 的三种类型
类型 | 描述 | 常见场景 |
---|---|---|
反射型 XSS | 恶意脚本通过 URL 参数传入,立即被页面“反射”回来 | 搜索框、跳转链接 |
存储型 XSS | 恶意脚本被存入数据库,所有访问者都会被攻击 | 评论区、留言板 |
DOM 型 XSS | 前端 JavaScript 操作 DOM 时未做过滤 | innerHTML 、document.write 等操作 |
XSS 的危害
窃取用户 Cookie(包括登录凭证)
模拟用户操作(如发帖、转账)
页面篡改(钓鱼、广告注入)
获取用户输入(键盘记录)
传播蠕虫病毒或恶意脚本
如何防范 XSS
对用户输入进行过滤和转义
特殊字符如
<
,>
,"
,'
应该被编码为 HTML 实体
使用安全的模板引擎
如 Vue、React 默认会自动转义内容
设置内容安全策略(CSP)
限制哪些脚本可以执行
避免使用
innerHTML
等危险 API改用
textContent
、createElement
等安全方式
什么是 HttpOnly Cookie?
HttpOnly 是 Cookie 的一个属性。
当设置为
HttpOnly
时,JavaScript 无法访问这个 Cookie(比如通过document.cookie
)。这样可以有效防止 XSS(跨站脚本攻击),因为攻击者即使注入了恶意脚本,也无法窃取这个 Cookie。
什么是 SameSite=Strict?
SameSite
是另一个 Cookie 属性,用于限制 Cookie 的跨站发送行为。设置为
Strict
时,Cookie 只会在同源请求中发送,不会在第三方网站发起的请求中附带这个 Cookie。这可以防止 CSRF(跨站请求伪造)攻击,因为攻击者无法在用户不知情的情况下利用 Cookie 发起敏感操作。
为什么这种方式安全?
属性 | 防护能力 |
---|---|
HttpOnly | 防止 XSS 窃取 Cookie |
SameSite=Strict | 防止 CSRF 攻击 |
结合这两个属性后,Token 存储在浏览器中既不会被恶意脚本访问,也不会被第三方网站滥用,是目前 Web 安全中推荐的做法之一。
实现目标
用户登录后,后端生成 Token(如 JWT)
后端通过响应设置 Cookie:HttpOnly + SameSite=None + Secure
前端通过
fetch
或axios
发起跨域请求,自动携带 Cookie后端验证 Cookie 中的 Token,实现免登录
Django 后端配置步骤
1. 安装依赖(如果用 JWT)
pip install djangorestframework djangorestframework-simplejwt
2. 配置 Django 跨域支持(CORS)
安装 CORS middleware:
pip install django-cors-headers
在 settings.py
中添加:
INSTALLED_APPS = [...'corsheaders',
]MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware',...
]CORS_ALLOWED_ORIGINS = ["http://localhost:3000", # 前端地址
]CORS_ALLOW_CREDENTIALS = True # 允许携带 Cookie
3. 登录视图设置 Cookie
假设你用 JWT 登录成功后,设置 Cookie:
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshTokenclass LoginView(APIView):def post(self, request):# 验证用户名密码(略)user = authenticate(...)if user:refresh = RefreshToken.for_user(user)access_token = str(refresh.access_token)response = Response({'message': '登录成功'})response.set_cookie(key='auth_token',value=access_token,httponly=True,samesite='None', # 跨域必须设置为 Nonesecure=True, # 必须是 HTTPSmax_age=7 * 24 * 60 * 60)return responsereturn Response({'error': '登录失败'}, status=401)
前端请求方式(Vue / React)
确保你设置了:
axios.post('https://api.example.com/login', data, {withCredentials: true
});
后续请求也要加 withCredentials: true
,浏览器才会自动携带 Cookie。
验证 Cookie 中的 Token
你可以在 Django 的中间件或视图中读取 Cookie:
token = request.COOKIES.get('auth_token')
然后用 JWT 工具验证它是否有效,提取用户信息。
总结关键点
项目 | 设置值 |
---|---|
Cookie 属性 | HttpOnly + SameSite=None + Secure |
Django CORS | CORS_ALLOW_CREDENTIALS = True |
前端请求 | withCredentials: true |
HTTPS | ✅ 必须(否则 Cookie 会被拒绝) |
为什么必须用 HTTPS?
当你设置 Cookie 的属性为 Secure=true
(这是跨域时必须的),浏览器就会强制要求:只有在 HTTPS 请求中才会保存和发送这个 Cookie。如果你用的是 HTTP,浏览器会直接忽略这个 Cookie,哪怕后端已经设置了。
开发环境怎么办?
在本地开发时,你可以考虑以下几种方式:
1. 使用本地 HTTPS(推荐)
用工具如mkcert 生成本地可信证书
配置前端和后端都支持 HTTPS
2. 临时关闭 Secure(仅限开发)
response.set_cookie('auth_token',value=token,httponly=True,samesite='None',secure=False # 仅开发环境可用,生产必须为 True
)
⚠️ 这种方式只适合本地调试,线上环境必须启用 HTTPS + Secure。
部署建议
一旦你部署到正式环境(比如 Vercel、Netlify、Render、阿里云等),一定要启用 HTTPS,否则 Cookie 就无法正常工作,尤其是跨域场景。
在企业级项目中,确实越来越多团队倾向于使用 HttpOnly Cookie 来存储敏感信息(尤其是身份令牌 Token),而不是 LocalStorage。这不是因为 LocalStorage 完全不可用,而是因为在安全性、合规性和用户信任方面,HttpOnly Cookie 更符合企业级要求。
为什么企业更偏向 HttpOnly Cookie?
安全性更高
LocalStorage 易受 XSS 攻击:如果网站存在漏洞,攻击者可以通过注入脚本读取 LocalStorage 中的 Token。
HttpOnly Cookie 无法被 JS 访问:即使有 XSS,攻击者也无法窃取 Cookie 内容。
自动携带机制
Cookie 会在请求时自动附带,无需前端手动拼接 Token。
更适合传统认证流程(如基于 Session 或 JWT 的 Cookie 验证)。
合规性与审计
企业项目常涉及 GDPR、ISO、SOC2 等合规要求,HttpOnly Cookie 更容易控制生命周期、撤销、审计。
与浏览器安全策略兼容
浏览器对 Cookie 的 SameSite、Secure、HttpOnly 等属性有明确支持,利于防止 CSRF 和数据泄露。
LocalStorage 仍然有用吗?
当然有用,尤其在以下场景:
使用场景 | 推荐方式 |
---|---|
非敏感数据(如 UI 状态) | ✅ LocalStorage |
Token + 前后端分离 + SPA | ⚠️ LocalStorage(需严格防 XSS) |
临时缓存、用户偏好设置 | ✅ LocalStorage |
如果你用 LocalStorage 存 Token,建议配合严格的 CSP(内容安全策略)、XSS 防护、Token 轮换机制。
企业项目常见做法
项目类型 | Token 存储方式 | 说明 |
---|---|---|
传统 Web 应用 | HttpOnly Cookie | 后端渲染页面,自动携带 Cookie |
前后端分离 + SPA | HttpOnly Cookie + CORS | 设置跨域、SameSite=None、Secure |
移动 App | LocalStorage / SecureStorage | 由客户端控制,非浏览器环境 |