zoukankan      html  css  js  c++  java
  • Django中csrf token验证原理

    我多年没维护的博客园,有一篇初学Django时的笔记,记录了关于django-csrftoekn使用笔记,当时几乎是照抄官网的使用示例,后来工作全是用的flask。博客园也没有维护。直到我的博客收到了如下评论,确实把我给问倒了,而且我也仔细研究了这个问题。
    1. Django是怎么验证csrfmiddlewaretoken合法性的?
    2. 每次刷新页面的时候<input>中的csrf的value都会更新,每次重复登录的时候cookie的csrf令牌都会刷新,那么这两个csrf-token有什么区别?

     
    image.png

    CSRF(Cross Site Request Forgery protection),中文简称跨站请求伪造。
    django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在 cookie 里。然后每次 POST 请求都会带上这个 token,
    这样就能避免被 CSRF 攻击。

    这样子看起来似乎没毛病,但是评论中的第三个问题,每次刷新页面,form表单中的token都会刷新,而cookie中的token却只在每次登录时刷新。我对csrftoken的验证方式起了疑问,后来看了一段官方文档的解释。

    When validating the ‘csrfmiddlewaretoken’ field value, only the secret, not the full token, is compared with the secret in the cookie value. This allows the use of ever-changing tokens. While each request may use its own token, the secret remains common to all.
    This check is done by CsrfViewMiddleware.

    官方文档中说到,检验token时,只比较secret是否和cookie中的secret值一样,而不是比较整个token。
    我又有疑问了,同一次登录,form表单中的token每次都会变,而cookie中的token不便,django把那个salt存储在哪里才能保证验证通过呢。直到看到源码。

    def _compare_salted_tokens(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(
            _unsalt_cipher_token(request_csrf_token),
            _unsalt_cipher_token(csrf_token),
        )
    
    def _unsalt_cipher_token(token):
        """
        Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
        CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
        the second half to produce the original secret.
        """
        salt = token[:CSRF_SECRET_LENGTH]
        token = token[CSRF_SECRET_LENGTH:]
        chars = CSRF_ALLOWED_CHARS
        pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
        secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
        return secret
    
    

    token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。
    django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法。
    同样也不难解释,为什么ajax请求时,需要从cookie中拿取token添加到请求头中。

    网上有不少关于django csrf token验证原理的文章都是错的,是因为他们根本不知道csrf-token的结构组成,我也是卡在第三条评论那.然后看了官方文档,和CsrfViewMiddleware中间件源码然后才恍然大悟。



    作者:邹霉霉
    链接:https://www.jianshu.com/p/7fbb60001018
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    Java1.7的HashMap源码分析-面试必备技能
    Springboot集成Swagger2
    springsecurity简单学习
    Java8的新特性
    HttpClient
    Filter的使用
    Spring拦截器和SpringAop实现
    运维工程师打怪升级进阶之路 V2.0
    欢迎加入微信交流群交流
    赞!7000 字学习笔记,一天搞定 MySQL
  • 原文地址:https://www.cnblogs.com/saolv/p/10995646.html
Copyright © 2011-2022 走看看