双Token的致命漏洞,你的系统安全吗?

内容总览

我与双Token的第一次邂逅,是在手搓自己的个人博客时遇到的。
我仍然很清晰地记得,我是如何实现的:

复制代码
我记得挺清楚,大致就是 短token与刷新token都放在了 请求头中,
如下:

旧的双Token实现方法

Token类型

  • Access Token: 短期有效token,用于API访问验证
  • Refresh Token: 长期有效token,用于刷新Access Token

传输方式

http 复制代码
x-access-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
x-refresh-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

核心流程

  1. 登录: 返回双token到响应体
  2. API调用: 前端在请求头携带Access Token
  3. Token刷新: Access Token过期时,使用Refresh Token获取新的双token
  4. 多点登录控制: 新登录时将旧Refresh Token加入黑名单

没有意识到的风险

复制代码
我仍然记得,当时兴致匆匆的,以为自己是个天才。
限于当时的学识,我从来没有考虑过:xss攻击。
现在回想起来真是让当时的自己感到脸红。
什么是XSS

XSS(跨站脚本攻击) 是一种常见的网络安全漏洞,攻击者通过在网页中注入恶意脚本,在用户浏览器中执行这些脚本来窃取信息或进行其他恶意操作。并且他主要有两种。

  1. 存储型 XSS

    • 恶意脚本被永久存储在服务器上(如数据库)
    • 当其他用户访问受影响页面时自动执行
    • 危害:盗取用户会话、cookie、个人信息
  2. 反射型 XSS

    • 恶意脚本通过 URL 参数等方式传递
    • 服务器直接返回包含恶意脚本的页面
    • 需要诱使用户点击恶意链接

简单来说,你可以将其看作一个,他会偷走你数据的小偷。

转机

后来在参加过几个项目后,我就开始为双Token的缺陷寻找解决方案。

最开始,我想到的方法是:

复制代码
Access + Refresh 均放 Cookie
当cookie中的HttpOnly设置为true时,脚本就偷不走我想保护的数据了。
因为此时两者(Access、Refresh)均不受 XSS(因为HttpOnly=true)

CSRF的风险

复制代码
当我以为,我已经找到了万全之策时,
殊不知,我只是从一个坑跳进了另一个坑。
什么是CSRF

你可以想象一下,接下来这个场景:

复制代码
- 你登录了网上银行(保持登录状态)
- 然后你访问了一个恶意网站
- 这个恶意网站悄悄向银行发送转账请求
- 因为浏览器会自动带上你的登录cookie,银行认为这是你的合法操作
- 结果:你的钱被转走了
常见的攻击步骤:
  1. 用户登录:用户登录正规网站,获得认证cookie
  2. 保持会话:用户没有登出,会话仍然有效
  3. 访问恶意网站:用户点击了攻击者发的链接或访问恶意网站
  4. 伪造请求:恶意网站自动向正规网站发送请求(携带用户的cookie)
  5. 执行操作:正规网站认为是用户的自愿操作
CSRF 与 XSS 的区别:
特性 CSRF XSS
攻击目标 利用用户的登录状态 窃取用户数据/会话
攻击方式 伪造请求 注入恶意脚本
依赖条件 用户已登录目标网站 网站存在输入漏洞
防护重点 请求来源验证 输入输出过滤

大概意思是说:CSRF是个骗子,而XSS是个小偷

新的解决方案

世上没有十全十美,而我现在采用的方式是:Refresh 用 HttpOnly Cookie +** Access 用 Header**

  • 客户端约定:
    • 请求头携带:x-access-token: <ACCESS_TOKEN>
    • 刷新时:浏览器自动携带 x-refresh-token Cookie(HttpOnly)
  • 后端行为:
    • 登录设置 x-refresh-token(HttpOnly, Path=/, Domain=当前域,secure 随 HTTPS)
    • 刷新接口只需读取 Cookie,不接收 x-refresh-token
    • 多点登录/黑名单:Redis 记录旧 Refresh,登录时旧值入黑名单并写入新值
  • 优点:
    • XSS 面显著降低:Refresh Token 不再可读
    • CSRF 可控:结合 SameSite、Origin 校验、Token 验签
    • 前端更简:无需存/传 Refresh Token
  • 注意点:
    • 跨域需开启凭证:前端 withCredentials: true;后端 CORS 需 Access-Control-Allow-Credentials: true 且明确 Allow-Origin

通过以上的折中的方案,可以既能享受到双token带来的便利,又能尽量降低损失。

如果你还有更好的建议,欢迎留言,评论( •̀ ω •́ )✧

拓展:

跨域是什么

浏览器把"同源"定义为三要素都相同:协议 + 域名(IP) + 端口

只要有一个不同,就叫跨域,会触发 CORS 限制。

例子:

  • http://192.168.1.10:3000http://192.168.1.10:8002:端口不同,跨域
  • http://localhost:3000http://127.0.0.1:3000:域名不同,跨域
  • http://https://:协议不同,跨域
  • name / value:Cookie 的名字和值
  • domain:限定哪个域名可以收到这个 Cookie
  • path :限定哪个路径可以收到这个 Cookie(如 / 代表全站)
  • expires / maxAge:过期时间(maxAge 是秒;expires 是具体时间点)
  • secure:只允许在 HTTPS 连接下发送
  • httpOnly:JS 无法读取(document.cookie 看不到),防 XSS
  • sameSite :控制跨站请求是否携带 Cookie
    • Lax:默认,跨站的普通请求不带,安全和可用平衡
    • Strict:最严格,跨站一律不带
    • None :跨站也带,但必须配合 secure=true(HTTPS)
go 复制代码
// 判断 host 是否是 IP 地址;IP 访问下不要设置 domain
   if net.ParseIP(host) != nil {
   	c.SetCookie(name, value, maxAge, "/", "", c.Request.TLS != nil, false)
   	return
   }
   // 域名访问:设置 domain 为主机名
   // 设置 SameSite 为 Lax(默认),如需 Strict 需显式调用 c.SetSameSite(http.SameSiteStrictMode)
   // 这里保持默认 Lax 以平衡安全性与体验
   c.SetCookie(name, value, maxAge, "/", host, c.Request.TLS != nil, false)
相关推荐
深盾科技2 小时前
Windows 11 24H2内核堆栈保护:系统安全新盾牌
安全·系统安全
普通网友2 小时前
等保2.0合规指南:三级系统安全要求与落地
安全·系统安全
Guheyunyi12 小时前
智能守护:视频安全监测系统的演进与未来
大数据·人工智能·科技·安全·信息可视化
Traced back13 小时前
WinForms 线程安全三剑客详解
安全·c#·winform
汉堡包00113 小时前
【网安基础】--内网代理转发基本流程(正向与反向代理)
安全·web安全·php
桌面运维家15 小时前
vDisk VOI/IDV权限管理怎么做?安全方案详解
安全
世界尽头与你15 小时前
(修复方案)kibana 未授权访问漏洞
安全·网络安全·渗透测试
xixixi7777716 小时前
今日 AI 、通信、安全行业前沿日报(2026 年 2 月 4 日,星期三)
大数据·人工智能·安全·ai·大模型·通信·卫星通信
蓝队云计算17 小时前
蓝队云部署OpenClaw深度指南:避坑、优化与安全配置,从能用做到好用
运维·安全·云计算