【一】csrf跨站请求
CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的网络攻击方式。
eg:钓鱼网站,看起来和正规的网站一模一样,但是后端进行了篡改
(1)案例
1.正常网站
<form action="" method="post">
<p>bank_card <input type="text" name="bank_card"></p>
<p>password <input type="text" name="password"></p>
<p>to_bank_card <input type="text" name="to_bank_card"></p>
<p>money <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
2.钓鱼网站--》写了一个输入框但是不指定name,一个隐藏的输入框写死指定了name和value,所以在提交表单时,就会打到黑客所指定的账户
<h1>这是钓鱼的转账页面</h1>
<form action="" method="post">
<p>bank_card <input type="text" name="bank_card"></p>
<p>password <input type="text" name="password"></p>
<p>to_bank_card <input type="text"></p>
<p><input type="text" name="to_bank_card" style="display: none" value="96963636"></p>
<p>money <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
3.后端逻辑和正常的网站是一样的
def transform(request):
if request.method == "POST":
# 自己的账户和取款密码
bank_card = request.POST.get("bank_card")
password = request.POST.get("password")
# 目标账户
to_bank_card = request.POST.get("to_bank_card")
money = request.POST.get("money")
message = f"当前账户 {bank_card} 向目标账户 {to_bank_card} 转账了 {money}"
print(message)
return HttpResponse(message)
return render(request, "transform.html", locals())
(2)现在的保护措施
(1)使用CSRF令牌
● 在用户的请求中添加随机生成的令牌,并将该令牌保存在用户会话中。
● 每次提交请求时都会验证该令牌,以确保请求是合法的。
(2)启用SameSite属性:
● 将Cookie的SameSite属性设置为Strict或Lax,以限制跨站请求。
● 这可以在一定程度上缓解CSRF攻击。
(3)严格验证请求来源
● 服务器端可以验证请求的来源是否为预期的网站域名
● 例如检查HTTP Referer头部。
(4)使用验证码
● 在敏感操作(如转账、更改密码等)上使用验证码
● 增加用户身份验证的防护。
(3)CSRF令牌验证
csrf校验是一种用于防止跨站请求伪造(Cross-Site Request Forgery)攻击的安全措施。
"""针对csrf相关的校验有很多种方式 django只是提供了一些而已"""
1.模板语法# form表单直接写{% csrf_token %}就可以了--》针对post请求
# 每一个请求过来的时候 都去生成一个随机的令牌
<form action="" method="post">
{% csrf_token %}---> 在前端会自动生成一个csrf,给这个页面标识
<p>当前账户:<input type="text" name="current_user"></p>
<p>目标账户:<input type="text" name="target_user"></p>
<p>转账金额:<input type="text" name="money"></p>
<input type="submit">
</form>
2.ajax请求
1.方式1:页面任意位置先写{% csrf_token %} 之后获取数据 'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()
并且不能写这两个参数否则会csrf令牌会失效,因为浏览器不会进行校验
// Ajax发送文件必须添加的两个参数
// 不需要使用任何编码 - Django后端能自动识别 formdata 对象
contentType: false,
// 告诉浏览器不要对我的数据进行任何处理
processData: false,
2.方式2:模板语法直接获取
'csrfmiddlewaretoken':{{ csrf_token }}
"""通用解决方案:js脚本自动处理"""
也只能适用于ajax提交 form表单还是需要额外指定
""" 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);
}
}
});"""
(4)csrf相关装饰器
from django.views.decorators.csrf import csrf_exempt,csrf_protect
"""
csrf_exempt
忽略csrf校验
csrf_protect
开启csrf校验
"""
# 针对FBV
@csrf_protect或者@csrf_exempt
def login(request):
return render(request,'login.html')
# 针对CBV
csrf_protect 三种CBV添加装饰器的方式都可以
csrf_exempt 只有一种方式可以生效(给重写的dispatch方法装),把全局校验打开
【二】Auth模块
# django提供给你快速完成用户相关功能的模块
用户相关功能:创建、认证、编辑...
# django也配套提供了一张'用户表'
执行数据库迁移命令之后默认产生的auth_user
# django自带的admin后台管理用户登录参考的就是auth_user表
创建admin后台管理员用户:run manage.py task>>:createsuperuser
自动对用户密码进行加密处理并保存
接下来会
让你写一个用户名,不写会是你本机名
写密码--》y
(1)auth模块方法大全
auth_user表是django自带的系统表,用不了orm,那么如何操作呢
from django.contrib import auth
# 1.验证用户名和密码是否正确
auth.authenticate()
eg:user_obj=auth.authenticate(request,username=username,password=password)--->user_obj的结果是一个用户对象,如果没有匹配上就是None
# 2.保存用户登录状态
auth.login()
eg:auth.login(request,用户对象user_obj)
# 3.查看是否登录
request.user获取当前登录的用户对象,或者是匿名用户
# 4.判断当前用户是否登录
request.user.is_authenticated()---》返回的是布尔值
#5.当前登录的用户对象的属性
request.user.username--》数据库中的用户名
request.user.password-->数据库中的密文密码
request.user.last_login-->登录的时间
# 6.校验登录装饰器--》没登录会跳到什么页面
from django.contrib.auth.decorators import login_required
@login_required(login_url='/lg/') # 局部配置,想跳哪里跳哪里
@login_required # 全局配置--》去setting中指定LOGIN_URL路由
LOGIN_URL = '/lg/' # 需要在配置文件中添加配置
# 6.修改密码---》登录之后才能修改密码
request.user.check_password(old_pwd) --》比对旧密码是否正确,返回值是布尔值
request.user.set_password(new_pwd)--》设置密码
request.user.save()--》要对登陆的用户对象进行保存
# 7.注销登录--》用户登录之后才能
auth.logout(request)
# 8.注册用户
from django.contrib.auth.models import User
不能使用create因为这样写进去的密码不是密文,到时候auth模块拿的是加密后的密码进行比对
User.objects.create_superuser()--》超级管理员,必须多录一个超级管理员
User.objects.create_suser()--》普通用户
(2)对auth表扩展表字段
# 方式1:编写一对一表关系(了解)
# 方式2:类继承(推荐)
from django.contrib.auth.models import AbstractUser
class Users(AbstractUser):
# 编写AbstractUser类中没有的字段 不能冲突!!!
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
AUTH_USER_MODEL = 'app01.Users'--》在配置文件中要写一下这个,然后才会把我们写的表当成是auth_user表
"""
1.类继承之后 需要重新执行数据库迁移命令 并且库里面是第一次操作才可以
2.auth模块所有的方法都可以直接在自定义模型类上面使用
自动切换参照表
"""
ps:课下可以先继承表 之后才练习auth所有的方法