Django框架中的CSRF原理 发送POST请求该如何做?

鳄鱼君

发表文章数:643

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python » Django框架中的CSRF原理 发送POST请求该如何做?

如果你的页面存在POST请求,如果不注释掉settings.py文件中的django.middleware.csrf.CsrfViewMiddleware,会直接出现403错误,那么现在打开它,做一下测试,看是否出现错误。

这其实是django内部帮我们做的一次防护,get请求没有限制,post请求的时候django会先去找csrf生成的随机字符串,现在是没有的,django没找到就会报错。既然django需要这个随机字符串,我们给它就是了。可以在login.html模板中form表单里面添加:{{ csrf_token }},然后再次尝试,你就会在登录页面看到django帮我们生成的随机字符串,但是一般不会让这个随机字符串显示在页面中,可以修改为:{% csrf_token %},这样django会将这个随机字符串放在html的value属性中,页面是看不到,在我们呢后台可以拿到这个随机字符串,然后我们带着这个随机字符串去发送POST请求。

在Cookie中会存在一个csrftoken,两者是一样的,我们的后台也可以从cookie中取它。做一个简单的例子,这里还是需要jquery.js和jquery.cookie.js,没有的下载即可。

那么你可能需要知道django.middleware.csrf.CsrfViewMiddleware做了什么事情,这个可以导入查看一下源代码,就像这样:from django.middleware.csrf import CsrfViewMiddleware,你就随便看看,有没有什么发现,大约在304行出现了下面的代码,我只截取一部分,就在process_view函数中:

request_csrf_token = ""
if request.method == "POST":
    try:
        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    except OSError:
        # Handle a broken connection before we've completed reading
        # the POST data. process_view shouldn't raise any
        # exceptions, so we'll ignore and serve the user a 403
        # (assuming they're still listening, which they probably
        # aren't because of the error).
        pass

if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

request_csrf_token = _sanitize_token(request_csrf_token)
if not _compare_salted_tokens(request_csrf_token, csrf_token):
    return self._reject(request, REASON_BAD_TOKEN)

现在我们可以把目光放在settings.CSRF_HEADER_NAME上,这个是什么,我们可以打印一下,采用下面的代码:

def login(request):
    from django.conf import settings
    print(settings.CSRF_HEADER_NAME)  #HTTP_X_CSRFTOKEN
    if request.method=='GET':
        return render(request,'login.html')
    if request.method=='POST':
        pass

可以看到在控制台输出了HTTP_X_CSRFTOKEN,这其实就是请求头中的信息,也就是说HTTP_X_CSRFTOKEN对应的值是token,但是请求头真实的名字叫:X-CSRFtoken,怎么知道的呢,还是做一下测试,使用ajax发送post请求的时候带上一个headers就可以了,假设设置一个kkkkkkkkkkkk的请求头,看一下结果是什么:

Django框架中的CSRF原理 发送POST请求该如何做?

可以看到django在自动在请求头上添加一个HTTP,所以说HTTP_X_CSRFTOKEN的真实值是X-CSRFtoken,那么现在就知道该如何添加请求头的信息了,代码参考:

<script type="text/javascript" src="/static/jquery-3.4.1.js"></script>
<script type="text/javascript" src="/static/jquery.cookie.js"></script>
<script>
    $(function () {
        var csrftoken=$.cookie('csrftoken');
        console.log(csrftoken);
        $('#bt').click(function () {  {# 绑定事件,发送ajax请求 #}
            $.ajax({
                url:'/login/',
                type:'POST',
                data:{'user':'root','pwd':'123'},
                headers:{'X-CSRFtoken':$.cookie('csrftoken')},  {# 从cookie中获取csrftoken #}
                success:function (data) {

                }
            })
        })
    })
</script>

需要注意的是请求头信息,为什么不是X_CSRFTOKEN呢?因为在django中不允许出现_,允许使用-来代替,所以我们设置的是X-CSRFtoken。这样一来我们打开settings.py中的csrf呢一行,测试一下代码是否可以发送POST请求,结果肯定是可以的,这里不再做演示了!

使用form表单发送post请求和使用ajax发送post请求都是类似的,重点就是这个csrftoken去哪里获取。现在我需要把所有的ajax请求都加上这个headers,我们使用上面的方法会有点麻烦,可以使用ajax为我们提供的方法:

<script type="text/javascript" src="/static/jquery-3.4.1.js"></script>
<script type="text/javascript" src="/static/jquery.cookie.js"></script>
<script>
    $(function () {
        {# xhr  :是xmlHttpRequest 对象#}
        $.ajaxSetup({
           beforeSend:function (xhr,settings) {   {# 在发送之前会先执行这个函数 全局配置 #}
                xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken')) ; {# 设置请求头 #}
           }
        });

        $('#bt').click(function () {  {# 绑定事件,发送ajax请求 #}
            $.ajax({
                url:'/login/',
                type:'POST',
                data:{'user':'root','pwd':'123'},
                success:function (data) {

                }
            })
        })
    })
</script>

那么这样对于GET请求也会添加上请求头,我们不想添加的话,可以在内部做一个判断,只对POST请求添加headers:

<script>
    $(function () {
        function csrfSafeMethod(method){
             return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }  {# 通过这个函数进行判断 #}
        $.ajaxSetup({
           beforeSend:function (xhr,settings) {   {# 在发送之前会先执行这个函数 全局配置 #}
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) { {# 通过settings.type拿到提交的方式 #}
                    xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken')) ; {# 设置请求头 #}
                }
           }
        });

        $('#bt').click(function () {  {# 绑定事件,发送ajax请求 #}
            $.ajax({
                url:'/login/',
                type:'POST',
                data:{'user':'root','pwd':'123'},
                success:function (data) {

                }
            })
        })
    })
</script>

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Django框架中的CSRF原理 发送POST请求该如何做?》 发布于2020-04-25

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

8 + 6 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册