Django中CSRF验证机制解析:为何不同令牌仍能通过校验?
Django CSRF令牌看似不同却验证通过的原因
这是因为Django的CSRF令牌采用了带随机掩码的设计,表面不同的令牌本质上对应同一个原始校验值,验证时会先解掩码再比较。
从你提供的代码看核心逻辑
_does_token_match函数并没有直接对比输入的两个令牌字符串,而是先对两个令牌分别调用_unmask_cipher_token进行解掩码处理,再用constant_time_compare比较处理后的结果:
def _does_token_match(request_csrf_token, csrf_token): # Assume both arguments are sanitized -- that is, strings of # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS. return constant_time_compare( _unmask_cipher_token(request_csrf_token), _unmask_cipher_token(csrf_token), )
Django CSRF令牌的生成机制
Django的CSRF令牌由两部分组成:
- 一个固定存储在用户session中的原始加密令牌(每个用户session对应唯一值)
- 一个每次生成时随机生成的掩码
返回给前端的令牌,是通过将原始令牌与随机掩码进行异或运算后得到的结果。这意味着:同一个session下,每次生成的表面令牌都会不同,但它们解掩码后都会还原出同一个原始加密令牌。
你的测试场景解释
你测试的两个令牌:
- Django自动生成返回的令牌
- 通过
get_token手动生成的令牌
都是基于同一个用户session中的原始加密令牌生成的,只是各自使用了不同的随机掩码。所以经过_unmask_cipher_token解掩码后,两者会得到完全相同的原始值,最终constant_time_compare返回True,验证通过。
这种设计的意义
带随机掩码的设计是为了提升安全性:即使攻击者嗅探到了某个前端令牌,也无法直接复用这个令牌发起CSRF攻击(因为下次请求生成的令牌掩码不同,但验证时只认解掩码后的原始值),同时避免了令牌长期固定带来的泄露风险。
内容的提问来源于stack exchange,提问作者BoostedAnimal
相关产品推荐
相关产品推荐

