django下的csrf防护机制

CSRF

一、什么是CSRF?

  CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。javascript

二、原理

从上图能够看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤 :html

  • 1.登陆受信任网站A,并在本地生成Cookie 。
  • 2.在不退出A的状况下,访问危险网站B。

ps:注意并非你退出了A后登录B就会没事,由于你不能保证你关闭浏览器了后,你本地的Cookie马上过时,你上次的会话已经结束。前端

CSRF预防机制

CSRF的防护能够从服务端和客户端两方面着手,防护效果是从服务端着手效果比较好,如今通常的CSRF防护也都在服务端进行。java

token防护的总体思路是jquery

  • 第一步:后端随机产生一个token,把这个token保存在SESSION状态中;同时,后端把这个token交给前端页面;ajax

  • 第二步:下次前端须要发起请求(好比发帖)的时候把这个token加入到请求数据或者头信息中,一块儿传给后端;django

  • 第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;后端

一、Django下的CSRF预防机制

django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在 cookie 里。而后每次 POST 请求都会带上这个 token,浏览器

这样就能避免被 CSRF 攻击。服务器

在 templete 中, 为每一个 POST form 增长一个 {% csrf_token %} tag. 以下: 

  1. 在返回的 HTTP 响应的 cookie 里,django 会为你添加一个 csrftoken 字段,其值为一个自动生成的 token
  2. 在全部的 POST 表单模板中,加一个{% csrf_token %} 标签,它的功能实际上是给form增长一个隐藏的input标签,以下

    <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">,而这个csrf_token = cookie.csrftoken,在渲染模板时context中有context['csrf_token'] = request.COOKIES['csrftoken']

  3. 在经过表单发送POST到服务器时,表单中包含了上面隐藏了crsrmiddlewaretoken这个input项,服务端收到后,django 会验证这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值是否同样。若是同样,则代表这是一个合法的请求,不然,这个请求多是来自于别人的 csrf 攻击,返回 403 Forbidden.

  4. 在经过 ajax 发送POST请求到服务器时,要求增长一个x-csrftoken header,其值为 cookie 里的 csrftoken 的值,服务湍收到后,django会验证这个请求的cookie里的csrftoken字段与ajax post消息头中的x-csrftoken header是否相同,若是相同,则代表是一个合法的请求

具体实现方法

django为用户实现防止跨站请求伪造的功能,经过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

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

注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

一、原理

  在客户端页面上添加csrftoken, 服务器端进行验证,服务器端验证的工做经过'django.middleware.csrf.CsrfViewMiddleware'这个中间层来完成。在django当中防护csrf攻击的方式有两种:

   1.在表单当中附加csrftoken

   2.经过request请求中添加X-CSRFToken请求头。

注意:Django默认对全部的POST请求都进行csrftoken验证,若验证失败则403错误侍候。

二、应用

一、在表单中附加csrftoken

veiw中设置返回值:
  return render_to_response('Account/Login.html',data,context_instance=RequestContext(request)) 
#在渲染模块时,使用 RequestContext。RequestContext 会处理 csrf_token 这个 tag,  从而自动为表单添加一个名为 csrfmiddlewaretoken 的 input 
     或者
     return render(request, 'xxx.html', data)   #使用render则会自动生成,不用ReqestContext
  
html中设置Token:
{% csrf_token %}

二、Ajax

对于传统的form,能够经过表单的方式将token再次发送到服务端,而对于ajax的话,使用以下方式。

from django.template.context import RequestContext
# Create your views here.
  
  
def test(request):
  
    if request.method == 'POST':
        print request.POST
        return HttpResponse('ok')
    return  render_to_response('app01/test.html',context_instance=RequestContext(request))
views.py

前端:

  二、在进行post提交时,获取Cookie当中的csrftoken并在请求中添加X-CSRFToken请求头, 该请求头的数据就是csrftoken。经过$.ajaxSetup方法设置AJAX请求的默认参数选项, 在每次ajax的POST请求时,添加X-CSRFToken请求头

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    {% csrf_token %}
  
    <input type="button" onclick="Do();"  value="Do it"/>
  
    <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
    <script src="/static/plugin/jquery/jquery.cookie.js"></script>
    <script type="text/javascript">
        var csrftoken = $.cookie('csrftoken');
  
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
        function Do(){
  
            $.ajax({
                url:"/app01/test/",
                data:{id:1},
                type:'POST',
                success:function(data){
                    console.log(data);
                }
            });
  
        }
    </script>
</body>
</html>
text.html
相关文章
相关标签/搜索