Django-CSRF跨站请求伪造

跨站请求伪造
    CSRF的全称是`Cross-site request forgery`,简单的意思就是用户在可信网站登录后获得可信cookie,未退出之前,访问了一个恶意网站,恶意网站夹带攻击性代码要求访问一个第三方网站,浏览器在接收到恶意网站的请求后,在用户不知情的情况下携带安全网站给的Cookie信息,向其发出请求。可信网站并不知道该请求其实是由恶意网站发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自恶意网站的恶意代码被执行
Django是如何防范CSRF的

猛戳

我们来看看CsrfViewMiddleware这个中间件的源码的一段内容

...
request_csrf_token = ""
if request.method == "POST":
    try:
        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') # POST请求是在这里获取到的
    except IOError:
        # 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, '') # ajax请求是在获取的

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的结果是这样的:

from django.conf import settings
print(settings.CSRF_HEADER_NAME)
>>> HTTP_X_CSRFTOKEN

Django使用django.middleware.csrf.CsrfViewMiddleware这一个中间件来完成验证的。在django中防御csrf攻击的方式有两种:

1. 在form表单中添加csrf_token
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>

    </style>
</head>
<body>
<div>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user">
        <input type="text" name="pwd">
        <input type="submit" value="提交">
    </form>
</div>
<script>

</script>
</body>
</html>

在form中加上这个{% csrf_token %}后其实他的本质是生成一个隐藏的input标签,并且input的value值是服务器端给网页get的时候生成的一个随机字符串,如下所示:

![](https://img2020.cnblogs.com/blog/1119052/202003/1119052-20200319130508084-1070406822.png)
在form提交的时候顺带将这个值发送给服务器做验证
2. 在header中添加X-CSRFToken
  • 当我们使用一般的ajax提交的时候
<script src="/static/jquery-1.12.4.js"></script> 
<script src="/static/jquery.cookie.js"></script>
<script>
    $(function () {
        $('#btn').click(function () {
            $.ajax({
                url:'/login/',
                type:'POST',
                data:$('#f1').serialize(),
                success:function () {
                }
            })
        })
    })
</script>

这样写ajax也会出现403CSRF verification failed. Request aborted.

那么我们的ajax就应该在header中加上CSRF_HEADER_NAME对应的值HTTP_X_CSRFTOKEN,但是由于django会在header的字段的首部自动加上HTTP_来作为区分,所以我们应该添加的真正值是X_CSRFTOKEN,但是又由于请求头中不能加下划线,所以只能写成这样了X-CSRFTOKEN,官方的书写方式是X-CSRFtoken,但是这两种都是可以的。

通过js来获取csrftoken这个cookie并添加到header中

正确的ajax请求应该是这样的

<script src="/static/jquery-1.12.4.js"></script> 
<script src="/static/jquery.cookie.js"></script>
<script>
    $(function () {
        $('#btn').click(function () {
            $.ajax({
                url:'/login/',
                type:'POST',
                headers:{"X-CSRFtoken": $.cookie('csrftoken'),}
                data:$('#f1').serialize(),
                success:function (arg) {
                    location.href="/index/"
                }
            })
        })
    })
</script>

3.将页面中所有的ajax请求都添加这个headers
$.ajaxSetup({
   beforeSend: function(xhr,settings){
       xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));
   }
});

django中选择使用CSRF

部分设定:from django.views.decorators.csrf import csrf_exempt,csrf_protect

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

全局设定:
使用中间件django.middleware.csrf.CsrfViewMiddleware

posted @ 2020-03-19 08:45  我的胡子有点扎  阅读(144)  评论(0编辑  收藏  举报