[Django系列]12.CSRF,装饰器和中间件

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

模拟CSRF攻击案例:余额怎么变少了?

小王和小李是某ICBC银行的2个正常的用户,用户小黑是一名黑客,也在该银行开了银行账户.三个用户的余额情况如下:

某天,小王给小李转账2000元成功后,收到了黑客小黑发了一个链接

小王打开连接后,显示的是一个幽默的大图:是男人就坚持600秒

万万没想到的是,小王银行卡里的钱少了100,更邪门的是,每打开一次这个界面,就会少100元!

小王一共点击了该页面10次,累计损失了1000元.

这是为何?
原来该icbc银行网站并没有开启csrf的校验,该位置位于settings.py的MIDDLEWARE下面django.middleware.csrf.CsrfViewMiddleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware', # 安全相关的中间件 比如:预防XSS攻击处理
    'django.contrib.sessions.middleware.SessionMiddleware',# session中间件
    'django.middleware.common.CommonMiddleware', # 自动给URL加斜杠和www的,等一些其他的小细节处理
   # 'django.middleware.csrf.CsrfViewMiddleware', # csrf攻击的中间件
    'django.contrib.auth.middleware.AuthenticationMiddleware', # 添加user这样一个属性,当然不仅仅这些,是一个授权的中间件
    'django.contrib.messages.middleware.MessageMiddleware', # message中间件
    'django.middleware.clickjacking.XFrameOptionsMiddleware', # 防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
    'account.middleware.mymiddleware.UserMiddleware'
]
启用该中间件,同时在输入的表单中,加入{% csrf_token %}
<form action="" method='POST'>
        {% csrf_token %}
        <table>
            <tbody>
                <tr>
                    <td><label for="">目标用户:</label></td>
                    <td><input type="text" name='username'></td>
                </tr>
                <tr>
                    <td><label for="">转账金额:</label></td>
                    <td><input type="text" name='money'></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value='确定'></td>
                </tr>
            </tbody>
        </table>
        {% if errors %}
            <p>{{errors}}</p>
        {% endif %}
    </form>
从那之后,无论小王再怎么不是男人,点开是男人坚持600秒的 那个钓鱼站点,都不会再损失钱了.

1.CSRF跨站攻击原因分析

  • 用户C在访问icbc站点A的时,登录完成后,A生成cookie交给C
  • C没有退出的情况下,访问了站点B
  • B在C没有退出登录的情况下,拿着C的cookie去访问A,进行转账操作.
  • 由于C并没有退出登录,A执行了B伪造C的请求,所以完成了转账.
分析该网站的源代码可以看到,转账操作其实是使用post方式提交了一个包含了用户名username,金额money的表单到当前的页面.

而钓鱼网站刚好是利用了这点漏洞,通过使用iframe隐藏框架,下挂一个隐藏的表单,这个表单跟银行转账的表单相似,参数一样,提交的内容一样.通过js脚本控制,加载该页面后,自动提交该表单的转账给小黑100元的请求.
  • 小王又正好在登录状态下,点开了这个网站.登录银行的会话sessionid依然存在.
  • 钓鱼网站恰好利用了该漏洞,进行跨域攻击.利用的是未退出的会话状态和未进行csrf防范的漏洞网站.

当网站开启了csrf校验后,每次向用户发送的页面,都带有csrfmiddlewaretoken这个中间件的跨站伪造校验码.每一次提交表单,都会将这个校验码回传,如果回传的校验码不正确,那么这个提交的操作将会被拒绝.达到了跨站攻击防御的目的.因为钓鱼网站没有得到csrf_token,无法通过验证.

相关代码下载http://test.gxticket.com:8080/pic/?name=csrf.rar

2.装饰器的用法

上个例子中,转账之前使用了装饰器login_required来检查是否已经登陆,那么是如何实现的呢?
在当前应用目录下面的decorators.py,用来存放我们需要使用的装饰器函数.
#coding: utf-8
from models import AccountModel
from django.shortcuts import redirect,reverse
login_required
def login_required(func):  #装饰器名称是login_required
    def wrapper(request,*args,**kwargs):  #内部定义个wrapper函数,传入request,和其他参数,wrapper是包装,封装的意思
        username = request.session.get('username',None) #通过传入的request从服务器备份的request.session中获取username.
        account = AccountModel.objects.filter(username=username).first() #查询数据库用户名是否存在,返回第一条记录对象
        if account: #如果存在,将传入的函数原封不动的返回
            return func(request,*args,**kwargs)
        else:
            return redirect(reverse('login')) #否则跳转到登陆界面
    return wrapper

3.中间件(Middleware)

3.1什么是中间件?
  • 中间件是在request和view之间以及view到response之间做的一些处理。
  • 使用中间件要注意放的顺序。通常是按照顺序执行.
#django常见的中间件及相关解释
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware', # 安全相关的中间件 比如:预防XSS攻击处理
    'django.contrib.sessions.middleware.SessionMiddleware',# session中间件
    'django.middleware.common.CommonMiddleware', # 自动给URL加斜杠和www的,等一些其他的小细节处理
    'django.middleware.csrf.CsrfViewMiddleware', # csrf攻击的中间件
    'django.contrib.auth.middleware.AuthenticationMiddleware', # 添加user这样一个属性,当然不仅仅这些,是一个授权的中间件
    'django.contrib.messages.middleware.MessageMiddleware', # message中间件
    'django.middleware.clickjacking.XFrameOptionsMiddleware', # 防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
    'account.middleware.mymiddleware.UserMiddleware'  #用户自定义的中间件
]
3.2中间件的实现过程
– 前台发起http请求过来是,首先要经过一些列的中间件

例如CommonMiddleware自动给URL加斜杠和www的,等一些其他的小细节处理,SessionMiddleware’,# 进行会话处理,CsrfViewMiddleware进行csrf攻击的处理,AuthenticationMiddleware认证处理,MessageMiddleware消息处理

– 经过这些中间件,其实类似于调用了一个有一个的函数去过滤.才到达views视图函数处理
– 处理完毕后,中间件也可以参与response的响应

3.3自定义中间件:
在应用目录下创建一个专门存放中间件的文件夹middleware,然后在里面包含一个init.py文件用来表示这是一个包,然后创建一个中间件的文件mymiddleware.py,用来存放指定的中间件:
#coding: utf8
from account.models import AccountModel
from django.utils.deprecation import MiddlewareMixin #需要从django.utils.deprecation导入MiddlewareMinxin模块# 1.10版本之后的中间件 
def UserMiddleware(get_response): #定义一个用户自定义的UserMiddleware中间件,传一个系统函数get_response作为参数
    def middleware(request): 
        # request中间件
        username = request.session.get('username',None) #从ression取出是否有该用户,如果没有则为空
        user = AccountModel.objects.filter(username=username).first() #检查数据库是否有该用户存在
        print 'middleware first'
        if user and not hasattr(request,'frontuser'): #弱用户存在于数据库,且用户没有设置属性frontuser
            setattr(request,'frontuser',user)        #对该用户设置frontuser属性,并返回.
        response = get_response(request)
        # response中间件
        return response
    return middleware
#1.10之前是封装成类
使用方法:在视图函数中,如果访问主页,已登录用户,具有frontuser属性,打印—,未登陆用户,打印++++
def index(request):
    if hasattr(request,'frontuser'): #是否有frontuser属性,有则说明已经登陆.这个属性就是上面提到的中间件添加的.
        print '------------------'
    else:
        print '++++++++++++++++++'
    return render(request,'index.html',{'user':'','comment':''})
使用中间件后查看是否登陆的效果.

总结

通过ICBC转账的一个实例,引出了CSRF的原理和分析,并提供了Django设置csrf的方法做了详细介绍说明.同时介绍了自定义装饰器的定义和用法,中间件的理论,以及如何自定义中间件.请重点掌握.
赞(1)
未经允许不得转载:http://www.yueguangzu.net逗逗网 » [Django系列]12.CSRF,装饰器和中间件
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址