csrf
csrf跨站请求伪造
1.简介
CSRF跨站点请求伪造可以理解为攻击者盗用了你的身份,以你的名义在网站上发送请求,对服务器来说这个请求完全合法,而攻击者就完成它所期望的操作,如以你发消息、盗取账户,转账等
2.模拟
钓鱼网站:一台计算机上两个服务端口启动,钓鱼网站提交地址改为正规网站的地址
<form action="http://127.0.0.1:8000/login/" method="post">
<p>username:
<input type="text" name="username">
</p>
<p>target_user:
<input type="text">
<input type="text" name="target_user" value="攻击者" style="display: none">
</p>
<p>money:
<input type="text" name="money">
</p>
<input type="submit">
</form>
3.预防
csrf策略:通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求
csrf操作
1.form表单
提交时会发送自动生成的一串随机字符串,这个随机字符串每次都不一样,正规网站会验证你的随机字符串是否正确
<form action="" method="post">
{% csrf_token %}
</form>
'如果是前后端分离就无法使用form表单方式,只能使用ajax'
2.ajax
2.1方式1:先编写csrf模板语法,然后根据标签查找和获取,在手动添加
<h1>真网站</h1>
{% csrf_token %}
<butto id="d1">点位</butto>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'barry','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
success:function (args) {
}
})
})
</script>
2.2方式2:直接利用模板语法即可,键然需要自己写,但值不需要标签查找和获取
<h1>真网站</h1>
<butto id="d1">点位</butto>
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:{'username':'barry','csrfmiddlewaretoken':'{{ csrf_token }}'},
success:function (args) {
}
})
})
</script>
2.3方式3:通用方式(利用js脚本)
扩展性最强
<script src="js文件路径"></script>
data:{'username':'barry'}
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 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');
csrf相关装饰器
1.部分校验或吧校验
1.1当整个网站都不校验csrf,但是局部视图函数需要校验
1.2当整个网站都校验csrf,但是去不视图函数不需要校验
2.FBV
from django.views.decorators.csrf import csrf_protect, csrf_exempt
2.1csrf_protect
全局不校验的情况下,装了@csrf_protect装饰器的函数才校验
2.2csrf_exempt
全局都校验的情况下,装了@csrf_exempt装饰器的函数才校验
3.CBV
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.utils.decorators import method_decorator
# 方式2:这个类下面所有的方法校验,可以使用name=指定给类中的那个方法校验
@method_decorator(csrf_protect, name='post')
class MyHome(views.View):
# 方式3:类里面所有的方法都会装上装饰器
@method_decorator(csrf_protect)
# 拦截了View的dispatch方法,但什么都没有改,继续执行父类的dispatch
def dispatch(self, request, *args, **kwargs):
super(MyHome, self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse('home get')
# 方式1:这个装饰器装饰的方法校验
@method_decorator(csrf_protect)
def post(self, request):
return HttpResponse('home post')
'''
csrf_exempt只有方式3:@method_decorator(csrf_exempt)有效,其他两种都无效
其他装饰器上述三种方式都有效
'''
auth
auth模块简介
1.django执行数据库迁移命令之后会产生一个auth_user表,该表可以配合auth模块做用户实现包括用户注册、用户登录、用户认证、注销、修改密码等功能
2.该表还是django admin后台管理默认的表
2.1django admin后台管理员创建
python manage.py createsuperuser
'输入用户名、邮箱、密码、确认密码'
auth模块常见方法
1.创建用户
from django.contrib.auth.models import User
1.1创建普通用户(无法加入后台管理)
User.objects.create_user(username=username)
1.2创建超级管理员(必须要给个邮箱)
User.objects.create_superuser(username, password, email)
2.校验用户名和密码是否正确
from django.contrib import auth
2.1自动校验数据(密码会自动加密在比对),数据正确则返回数据对象,数据错误则返回None
user_obj = auth.authenticate(request, username=username, password=password)
3.用户登录
3.1如果数据存在则保存用户登录状态,自动操作cookie和session
auth.login(request, user_obj)
4.判断用户是否登录
4.1判断当前用户是否登录,返回布尔值
request.user.is_authenticated()
5.获取登录用户对象
5.1当用户登录成功之后(执行了auth.login),该方法会返回当前登录用户对象
5.2当用户没有登录成功之后(没有执行auth.login),该方法会返回匿名用户对象
request.user
6.校验用户登录装饰器
from django.contrib.auth.decorators import login_required
6.1效验用户是否登录,默认跳转的登录地址比较复杂,在括号内可以自定义跳转的登录地址(局部配置)
@login_required(login_url='/login/')
6.2在settings.py文件中配置下列配置,@login_required将不需要配置跳转地址(跳转全局配置)
LOGIN_URL = '/login/'
7.校验密码是否正确
7.1校验原密码是否正确,将密码自动加密并校验,返回布尔值
is_right = request.user.check_password(obl_password)
8.修改密码
8.1修改密码
request.user.set_password(new_password)
8.2保存修改后的密码
request.user.save()
9.注销登录
9.1退出登录,自动清除cookie和session
auth.logout(request)
auth_user表切换
1.models.py
from django.contrib.auth.models import AbstractUser
class Userinfo(AbstractUser):
# 扩展auth_user表中没有的字段
phone = models.BigIntegerField()
2.settings.py
# 切换auth_user表配置
AUTH_USER_MODEL = 'app01.Userinfo'
'''
将原来的auth_user表变成Userinfo表,Userinfo表和auth_user表的功能都一样,只是多了扩展的字段
如果已经执行了数据库迁移,库中有auth_user表,则这个命令就不能用了
执行数据库迁移命令后,库中不会在创建auth_user表,而是app01_Userinfo表
'''
基于django中间件设计项目功能
1.模块导入
s1 = 'aaa.a' # 最小只能到py文件
import importlib
# 按点号切割成路径
res = importlib.import_module(s1)
print(res)
# <module 'templates.a' from 'D:\\py02\\aaa\\a.py'>
print(res.name)
# barry
2.简单的函数式封装
def send_qq(content):
print('qq消息通知', content)
def send_weixin(content):
print('微信消息通知', content)
def send_all(content):
send_qq(content)
send_weixin(content)
send_all('收到消息了吗')
3.配置文件拔插设计
import importlib
import settins
def send_all(content):
# 获取NOTIFY_FUNC_LIST里面一条条字符串
for i in settins.NOTIFY_FUNC_LIST: # 'django02.notify.qq.Qq'
# 切割字符串,获取切割后的字符串
module_path, class_str_name = i.rdplit('.', maxplit=1) # 'django02.notify.qq','Qq'
# 导module_path路径的模块
module = importlib.import_module(module_path)
# 从module模块中获取该模块的名字
class_name = getattr(module, class_str_name)
# 产生类名字的对象
obj = class_name()
# 使用对象send方法
obj.send(content)
3.1配置文件(settings.py)
# 各个功能的路径
NOTIFY_FUNC_LIST = [
'django02.notify.qq.Qq',
'django02.notify.weixin.weiXin',
]
3.2py文件
class Qq(object):
def __init__(self):
pass # 模拟发送qq之前,应该准备的代码环境
def send(self, content):
print('qq消息通知', content)