csrf跨站请求伪造

什么是跨站请求伪造

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack或者 session riding,通常缩写为 CSRF或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

CSRF攻击原理

CSRF攻击的大致方式如下:某用户登录了A网站,认证信息保存在cookie中。当用户访问攻击者创建的B网站时,攻击者通过在B网站发送一个伪造的请求提交到A网站服务器上,让A网站服务器误以为请求来自于自己的网站,于是执行响应的操作,该用户的信息边遭到了篡改。总结起来就是,攻击者利用用户在浏览器中保存的认证信息,向对应的站点发送伪造请求。用户的认证是通过保存在cookie中的数据实现,在发送请求是,只要浏览器中保存了对应的cookie,服务器端就会认为用户已经处于登录状态,而攻击者正是利用了这一机制。

CSRF校验策略

当处理非GET请求时,要想避免CSRF攻击,关键在判断请求是否来自自己的网站。理论上讲,通过HTTP referrer可以判断原站点从而避免CSRF攻击,但是referer很容易被修改和伪造,所以不能作为主要的防御措施。

除了在表单中加入校验码外,一般的做法是通过在客户端页面中加入伪随机数来防御CSRF攻击,这个伪随机数通过被称为CSRF令牌(token)。

在计算机语境中,令牌(token)指用于标记、验证和传递信息的字符,通常是通过一定算法生成的随机数。

在HTML中,POST方法的请求通过表单创建。我们把在服务器端创建的伪随机数(CSRF令牌)添加到表单中的隐藏字段里和session变量(即签名cookie)中,当用户提交表单时,这个令牌会和表单数据一起提交。在服务器端处理POST请求时,会对表单中的令牌值进行验证,如果表单中的令牌值和seesion中的令牌值相同,就说明请求来自自己的网站。因为CSRF令牌在用户向包含表单的页面发起GET请求时创建,并且在一定时间内过期,一般情况下攻击者无法获取到这个令牌值,所以我们可以有效地区分出请求的来源是否安全。

简单来说就是当网站给用户发送页面时,在页面中添加一个唯一标识,当向这个页面发送请求时,服务器会先校验是否有这个唯一标识,如果没有就拒绝。

在Django中使用CSRF校验

  1. 在settings.py中打开中间件'django.middleware.csrf.CsrfViewMiddleware',
  2. 添加

在form表单中使用csrf_token

<form action="" method="post">
     {% csrf_token %}
    ...
</form>

在ajax中使用csrf_token

方法一:

$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  data: {
    "username": "Tonny",
    "password": 123456,
    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
  },
  success: function (data) {
    console.log(data);
  }
})

方法二:

$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 从Cookie取csrf_token,并设置ajax请求头
  data: {"username": "Q1mi", "password": 123456},
  success: function (data) {
    console.log(data);
  }
})

方法三:

# 在static目录中创建静态文件:  ajax_csrf.js(名字随便起,调用时一样就行)
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('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);
    }
  }
});

# 之后在前台页面引入即可
<script src="/static/ajax_csrf.js"></script>

将下面的文件配置到你的Django项目的静态文件中,在html页面上通过导入该文件即可自动帮我们解决ajax提交post数据时校验csrf_token的问题,(导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的)

使用装饰器的csrf_token

针对FBV的装饰器

需求:只对某一个视图函数添加crsf校验或对某个视图函数不进行校验

  • 注意:使用此方法后,优先于中间件校验。
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def xxx(request):pass  # 这时即便中间件开启了csrf校验,此函数还是不会进行校验的

@csrf_protect
def xxx(request):pass  # 这时即便中间件没有开启csrf校验,此函数还是会进行校验

针对CBV的装饰器

# 导入模块
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator

# 方法一:在类里面的方法上面添加装饰器(对csrf_exempt不生效)
class MyView(views.View):
    # 3. 添加装饰器
    @method_decorator(csrf_protect)  # 使用此方法对class内的一个function生效
    def login(self, request):
        return HttpResponse('xxxx')


# 方法二:在类上面添加装饰器,装饰器使用name参数指定函数名(对csrf_exempt不生效)
@method_decorator(csrf_protect, name='login')
class MyView(views.View):
    def login(self, request):
        return HttpResponse('xxxx')


# 方法三:如果类中的方法太多,要对类里面所有的方法生效,可以使用重写类方法进行设置(对csrf_exempt生效)
class MyView(views.View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def login(self, request):
        return HttpResponse('xxxx')

注意:如果要对csrf_exempt生效,只能使用方法三!

posted @   树苗叶子  阅读(178)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示