zoukankan      html  css  js  c++  java
  • Django 安全之跨站点请求伪造(CSRF)保护

    Django 安全之跨站点请求伪造(CSRF)保护

    by:授客 QQ1033553122

     

    测试环境

    Win7

    Django 1.11

     

     

    跨站点请求伪造(CSRF)保护

    中间件配置

    默认的CSRF中间件在MIDDLEWARE中定义并处于激活状态。如果需要变更默认配置,修改settings.py中的MIDDLEWARE配置即可,如下,假设要开启CSRF,确保列表包含  'django.middleware.csrf.CsrfViewMiddleware',并且其位置位于其它会对CSRF攻击进行处理的中间件之前,假设要禁用CSRF中间件,去掉列表中的'django.middleware.csrf.CsrfViewMiddleware',或者采用注释方式,把 'django.middleware.csrf.CsrfViewMiddleware' 注释掉。注意:更改配置后需要重启web服务器。

     
    MIDDLEWARE = [
        ……,
    'django.middleware.csrf.CsrfViewMiddleware',
    ……
    ]

     

    如果CSRF中间件被禁用(不推荐),又想对特定视图启用中间件保护,则可以针对特定视图使用csrf_protect()修饰器,如下:

    from django.views.decorators.csrf import csrf_protect
     
    @csrf_protect
    def specific_view(request):
        do something
     
    参考链接:https://docs.djangoproject.com/en/2.1/ref/csrf/#django.views.decorators.csrf.csrf_protect
     
     

    相反的,如果中间件已经开启,但是又不想针对特定视图使用中间件保护,则可以针对特定视图使用csrf_exempt() 修饰器

    from django.views.decorators.csrf import csrf_exempt
     
     
    @csrf_exempt
    def specific_view(request):
    do something
     
    参考链接:https://docs.djangoproject.com/en/2.1/ref/csrf/#utilities

     

     

    html模板配置

    开启CSRF中间件的情况下,要在html模板中为使用post方法的form表单新增 csrf_token tag,如下:

     

    <form method="post">

    {% csrf_token %}

    <input ...>... </input>

    ...

    </form>

     

    注意:如果被渲染的view视图未使用csrf_token模板标签,Django可能不会设置CSRF token cookie。这种情况下,假如有必要,可以使用Django提供的 @ensure_csrf_cookie()装饰器强制view视图发送CSRF cookie。

     

    from django.views.decorators.csrf import ensure_csrf_cookie

     

    @ensure_csrf_cookie()

    def specific_view(request):
    do something

     

    view视图函数

    对应的视图函数中,确保使用了RequestContext来渲染response,以便{%csrf_token %}可以正常运行。因为 render()函数使用了RequestContext,所以一般的view中,使用render()也是可以的。

     

     

    前端js脚本

    注意:如果已开启CSRF 的情况下,需要给请求添加X_CSRFTOKEN 请求头,否则会报403错误

    /**

     * 验证不需要CSRF保护的HTTP方法名(GET|HEAD|OPTIONS|TRACE

     */

    function csrfSafeMethod(method) {

    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));

    }

     

    /**

     * 获取cookie项的值

     * key:cookie名称

     */

    function getCookie(key) {

     

    var cookies = document.cookie.split(';'); // 获取每个cookie项(不含会话id)

    var value = undefined;

    for (var i in cookies) {

    var kv = cookies[i].split('='); // 每个cookie项的名称和cookie的值

    var temp_key = kv[0].replace(' ', ''); // 获取的cookie项有多个值,第二个开始,键 的值 的左侧会加个空格

    if (key == temp_key) {

    var value = kv[1];

    break;

            }

        }

    return value;

    }

     

     

    /**

     * Created by shouke on 2018/11/1.

     */

     

    //全局变量设置

    var loginURL = '/platform/api/v1/login'; // 注册api地址

    var loginFormID = 'login-form';           // 登录表单ID

    var registerRightNowID = 'registerRightNow' // 立即注册链接ID

     

    /**

     * 初始化

     */

    $(document).ready(function() {

    // 设置顶部导航

    setTopNav();

     

    var resources = $.session.get('resources');

    if (resources) {

    resources = JSON.parse(resources).resources;

    // 设置立即注册url

    $("#" + registerRightNowID).attr("href", resources.register_url.url);

     } else {

    alert('获取资源失败,导致设置立即注册连接失败');

    }

     

    // 为登录表单绑定提交事件

    $('#' + loginFormID).submit(function() {

    /**

             * 提交登录信息

             */

    var dataArray = $('#' + loginFormID).serializeArray();

     

    var data = {}

    $.each(dataArray, function () {

    data[this.name] = this.value;

          });

     

    var csrfToken = getCookie('csrftoken');

    if (csrfToken == undefined) {

    alert('获取Cookie失败');

    return false;

          }

     

    $.ajax({

    type: "POST",

    url: loginURL,

    async: false,

    data: data,

    beforeSend: function (xhr, settings) {

    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {

                        xhr.setRequestHeader("X-CSRFTOKEN", csrfToken);

                 }

             },

    success: function (result) {

    if (result.success == 'true') {

    alert(result.msg);

    $.session.remove('resources');                // 清空登录前获取的资源,以便重新获取资源

                     // 重定向返回登录前的页面

    window.location.href = result.next;

                } else {

    alert(result.msg + "," + result.reason);

                }

           },

    error: function(XmlHttpRequest, textStatus, errorThrown) {

    alert('登录请求失败' + XmlHttpRequest.responseText);

           }

        });

    return false;

    });

    });

     

    注意:这里最后面添加的return false; 主要是用于 避免跳转到django后台的返回结果数据页

     

     

    参考链接

    https://docs.djangoproject.com/en/2.1/ref/csrf/#using-csrf

    https://docs.djangoproject.com/en/2.1/topics/security/#cross-site-request-forgery-csrf-protection

     

     

  • 相关阅读:
    Git教程
    Android 使用AIDL调用外部服务
    Android 不同文件名介绍
    详解Android首选项框架ListPreference
    Android 使用Telephony API
    Android ImageButton android:scaleType
    Java实现二维码QRCode的编码和解码
    java二维码生成与解析代码实现
    Java中转UTC时间字符串(含有T Z)为local时间
    http://www.yihaomen.com/article/java/302.htm
  • 原文地址:https://www.cnblogs.com/shouke/p/13624458.html
Copyright © 2011-2022 走看看