JWT 用对了是一件趁手的工具,用错了却可能比传统会话更危险,因为它把信任完全押在了正确的实现上。围绕 JWT 出现过不少真实的安全事故,而它们大多源于少数几类反复出现的错误。了解这些陷阱,并不需要你成为密码学专家,只需要养成几条稳妥的习惯,就能避开最常被攻击者利用的弱点。

接受"none"算法

JWT 头部声明了使用哪种签名算法,其中规范里有一个特殊值表示"不签名"。如果你的验证逻辑盲目相信头部里写的算法,攻击者就可以把算法改成 none、去掉签名,然后伪造任意载荷。服务器若不加判断地接受,就等于放弃了所有保护。

防范方法很直接:在服务端明确指定并强制要求使用的算法,绝不让令牌头部来决定该用哪种算法验证。任何声称"无需签名"的令牌都应被直接拒绝。

对称与非对称算法的混淆

另一个经典漏洞,是攻击者把本应用非对称算法(如 RS256)验证的系统,诱导成用对称算法(如 HS256)来验证。在非对称方案里,公钥是公开的;如果服务器被骗成用这个公开的公钥当作对称密钥去验证,攻击者就能用它伪造出合法签名。

避免的办法同样是不信任令牌头部:在代码里固定使用预期的算法和正确的密钥类型,而不是根据头部动态切换。算法的选择应当由服务器决定,而非令牌。

弱密钥与密钥管理疏忽

对称签名的安全性完全取决于密钥的强度。如果你用了一个简短、可猜测的密钥,攻击者就可能通过暴力破解还原它,进而伪造任意令牌。把密钥硬编码进代码、提交到代码仓库,或在多个环境间共用同一个密钥,都会大幅放大风险。

稳妥的做法是使用足够长、足够随机的密钥,把它存放在安全的配置或密钥管理服务里,并支持定期轮换。密钥一旦泄露,整套认证就形同虚设。

忘记验证关键声明

很多实现只检查了签名,却忘了校验载荷里的关键声明。一个签名有效但早已过期的令牌,如果不检查过期时间,就会被继续接受。同样,不校验受众和签发者,可能让一个为别处签发的令牌在你的系统里被误用。

完整的验证应当包括:签名正确、令牌未过期、签发者可信、受众匹配。把这些校验都做齐,才算真正验证了一个令牌,而不只是确认它"形状对"。

把令牌放进不安全的位置

令牌一旦泄露,攻击者就能冒充用户,直到它过期。如果把令牌存在容易被脚本读取的地方,跨站脚本攻击就可能窃取它;如果通过不安全的连接传输,它就可能在途中被截获。存放和传输令牌的方式,和签名本身一样重要。

务必只通过加密连接传输令牌,谨慎选择存储位置以降低被脚本窃取的风险,并避免把令牌暴露在 URL 这类容易被日志记录或分享的地方。

有效期过长且无法撤销

JWT 无状态的代价是难以撤销。如果你又把有效期设得很长,一个被盗的令牌就会在很长时间里持续有效,哪怕用户已经登出、密码已经修改。攻击者拿到这样一个令牌,几乎等于拿到了长期通行证。

更稳妥的模式是把访问令牌的有效期设得很短,再用刷新令牌按需换取新的访问令牌;必要时还可以维护一个撤销名单。短有效期把泄露造成的窗口压到最小,是抵御令牌被盗的关键一招。

把安全建立在习惯之上

纵观这些错误会发现一个共同点:它们几乎都源于"过度信任令牌本身"。无论是相信头部里的算法、忽略声明校验,还是放任过长有效期,根子都在于把本该由服务器把控的决定,交给了攻击者可以操纵的令牌。

把安全建立在稳定的习惯上——强制算法、校验全部关键声明、用强密钥、缩短有效期、保护好传输与存储——你就能让 JWT 回到它该有的样子:一个可靠而非脆弱的认证机制。