目录
- 一、什么是csrf?
- 二、csrf原理
- 三、如何预防CSRF?
- 1、提交验证码
- 2、Referer Check
- 3、token验证
- 4、在HTTP头中自己定义属性并验证
- 四、form表单中如何通过csrf校验?
- 五、AJAX如何通过csrf校验?
- 六、CSRF相关装饰器
- 1、登录认证装饰器
- 2、校验用户是否登录装饰器
- 七、Django用户相关自带功能模块 auth
- 1、auth方法大全
- 2、如何扩展auth_user表?
一、什么是csrf?
CSRF即跨站请求攻击。简单的说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己以前认证过的站点并运行一些操作(如发邮件,发消息,甚至财产操作(如转账和购买商品))。因为浏览器之前认证过,所以被访问的站点会绝点是这是真正的用户操作而去运行。
这就利用了web中用户身份认证验证的一个漏洞:简单的身份验证仅仅能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
其实可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包含:以你的名义发送邮件;发消息;盗取你的账号;甚至于购买商品、虚拟货币转账......造成的问题包含个人隐私泄露以及财产安全。
大白话总结:自己准备一个拥有默认值(你的银行卡号)的input框,隐藏起来。用户输入转账的input框,没有name属性。用户发送转账请求的时候,后端拿到的是你已经准备好的银行卡号,而不是用户输入的。
跨站请求伪造csrf
钓鱼网站
本质搭建一个跟正常网站一模一样的页面
用户在该页面上完成转账功能
转账的请求确实是朝着正常网站的服务端提交
唯一不同的在于收款账户人不同
给用户书写form表单 对方账户的input没有name属性
你自己悄悄提前写好了一个具有默认的并且是隐藏的具有name属性的input
模拟钓鱼网站
二、csrf原理
从上图能够看出,要完毕一次CSRF攻击,受害者必须依次完毕两个步骤:
登录受信任站点A,并在本地生成Cookie。
在不登出A的情况下,訪问危急站点B。
三、如何预防CSRF?
1、提交验证码
在表单中添加一个随机的数字或字母验证码。通过强制用户和应用进行交互。来有效地遏制CSRF攻击。
2、Referer Check
检查假设是非正常页面过来的请求,则极有可能是CSRF攻击。
3、token验证
(1)在 HTTP 请求中以參数的形式添加一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,假设请求中没有 token 或者 token 内容不对,则觉得可能是 CSRF 攻击而拒绝该请求。
(2)token必须足够随机
(3)敏感的操作应该使用POST,而不是GET。比如表单提交。
4、在HTTP头中自己定义属性并验证
这样的方法也是使用 token 并进行验证。这里并非把 token 以參数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自己 定义的属性里。通过 XMLHttpRequest 这个类,能够一次性给全部该类请求加上 csrftoken 这个 HTTP 头属性。并把 token 值放入当中。这样攻克了上种方法在请求中添加 token 的不便。同一时候,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用操心 token 会透过 Referer 泄露到其它站点中去。
四、form表单中如何通过csrf校验?
你只需要在你的form表单内写一个 {% csrf_token %}
五、AJAX如何通过csrf校验?
第一种方式:自己手动获取
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
// 第一种方式 自己手动获取
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
success:function (data) {
alert(data)
}
})
})
第二种方式:利用模板语法
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
// 第二种方式 利用模板语法
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
success:function (data) {
alert(data)
}
})
})
第三种方式:通用方式 引入外部js文件 官网提供的方式
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
success:function (data) {
alert(data)
}
})
})
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);
}
}
});
六、CSRF相关装饰器
1、登录认证装饰器
使用的时候需要导入:
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
@csrf_exempt # 不校验csrf
@csrf_protect # 校验
使用方法
1.在指定函数头上装
@method_decorator(csrf_protect) # 第一种方式
def post(self,request):
return HttpResponse('post')
2.在类名头上指名道姓给某个方法装
@method_decorator(csrf_protect,name='post')
class MyHome(View):
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def post(self,request):
return HttpResponse('post')
def get(self,request):
return HttpResponse('get')
3.类中所有方法都装
class MyHome(View):
@method_decorator(csrf_protect) # 第三种 类中所有的方法都装
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def post(self,request):
return HttpResponse('post')
def get(self,request):
return HttpResponse('get')
2、校验用户是否登录装饰器
from django.contrib.auth.decorators import login_required
使用方式:
@login_required(login_url='/index/') 可以传参数,重定向到页面。这是是局部。
@login_required(login_url='/index/')
def yyy(request):
return HttpResponse('yyy页面')
全局修改参数方式:修改之后,影响全局。局部也可以修改。局部修改就用局部的
在settings.py中添加:LOGIN_URL = '/login/'
七、Django用户相关自带功能模块 auth
1、auth方法大全
1.创建用户
User.objects.create() # 密码是明文
User.objects.createuser() # 基本都用它
User.objects.createsuperuser() # 邮箱要给数据
2.校验用户名和密码是否正确
auth.authenticate(username=username,password=password) # 用户名和密码两个一个都不能少
# 该方法当用户名和密码正确的时候返回的用户对象 不正确返回None
3.保存登录状态
auth.login(request,user_obj) # 这一句执行之后 request.user获取当前登录的用户对象
4.如何判断当前用户是否登录 以及如何获取当前登录用户对象
request.user.is_authenticated() # 判断是否登录
request.user # 登录用户对象
5.校验用户是否登录
from django.contrib.auth.decorators import login_required
# 局部配置
@login_required(login_url='/login/')
def xxx(request):
return HttpResponse('xxx页面')
# 全局配置
配置文件中写以下代码
LOGIN_URL = '/login/'
@login_required
def xxx(request):
return HttpResponse('xxx页面')
# 如果两个都设置了 那么优先执行局部配置
6.修改密码
request.user.check_password(old_password) # 校验原密码是否正确
request.user.set_password(new_password)
request.user.save() # 一定要保存
7.注销功能
auth.logout(request) //删除了session值
2、如何扩展auth_user表?
# 1 利用一对一表关系()
# 2 利用类的继承
# 1 类的继承
from django.contrib.auth.models import User,AbstractUser
# Create your models here.
class Userinfo(AbstractUser):
phone = models.BigIntegerField()
avatar = models.FileField()
# 扩展的字段 尽量不要与原先表中的字段冲突
# 2 配置文件
AUTH_USER_MODEL = '应用名.表名'
"""
django就会将userinfo表来替换auth_user表
并且之前auth模块所有的功能不变 参照的也是userinfo表
"""