一、CSRF跨站请求伪造
简介
首先我们看到名称伪造就发现有端倪 CSRF跨站伪造 我们可以简单的理解成钓鱼网站
钓鱼网站会拥有一个跟银行app网页一样的界面 当我们输入转账人的时候确定转账
这个时候钓鱼网站就会把转账人收款的账号修改成自己的 所以有些网站就是这种黑钱的方法
模拟
一台计算机上面设置两个服务端不同的端口启动 钓鱼网站提交地址改为正规网站的地址
策防
CSRF策略:通过在返回的页面上添加一个独一无二的标识信息 从标识信息中查看返回的信息是否一致 如果不一致则说明有人截取了该信息
正规网站发现信息不一致则拒绝接收 此现象叫做403Forbidden 与此相关的策略就是我们中间件中的之前被注释的一行代码
MIDDLEWARE = [django.middleware.csrf.CsrfViewMiddleware]
Fake
<form method="post" action="http://127.0.0.1:8000/real/">
<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>
real.views
def real_html(request):
if request.method == 'POST':
username = request.POST.get('username')
target_user = request.POST.get('target_user')
money = request.POST.get('money')
print(f'用户{username}给{target_user}转账了{money}元!!!')
return render(request, 'real.html')
二、CSRF操作
如果我们想解决这个问题 就要针对Post请求 涉及到Post请求当前博客中提到过form表单以及Ajax
Post
post请求如果想阻止发生这种事情的话很简单 把注释打开 只要加上模版语法{%. csrf_token %}
我们点击右键检查会发现多一行input是由csrf创建的 当我们刷新一次页面就会获得不一样的字符串标识信息
这个时候我们真正的网站转账是可以通过 但是钓鱼网站就会显示403Forbidden
<form method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>target_user<input type="text" name="target_user"></p>
<p>Money:<input type="text" name="money"></p>
<input type="submit">
</form>
Ajax
方式1
先编写csrf模板语法 然后利用标签查找和值获取 手动添加 需要添加 {% csrf_token %}
data:{'username':'James','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
方法2
直接利用模板语法即可 不需要添加{% csrf_token %}
data:{'username':'James','csrfmiddlewaretoken':'{{ csrf_token }}'},
方式3
直接使用JS脚本 拓展性最高
<script src="/static/csrf.js"></script>
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装饰器相关操作
现在我们知道怎么操作CSRF但是当整个网站默认都不校验csrf 但是局部视图函数需要校验 如何处理
当整个网站默认都校验csrf 但是局部视图函数不需要校验 如何处理? 这个时候就需要使用到Django提供的两个装饰器
from django.views.decorators.csrf import csrf_protect, csrf_exempt
csrf_protect表示检验csrf csrf_exmpt表示不检验csrf
FBV
----------------------------------------------
'''首先将中间件中的注释掉django.middleware.csrf.CsrfViewMiddleware'''
html
<form action="/fbv/" method="post"> # 直接发送post请求
<input type="submit">
</form>
'''如果想让检测加上装饰器则是csrf_protect 不想检测就是csrf_exempt'''
views
from django.views.decorators.csrf import csrf_protect, csrf_exempt
@csrf_protect # 检验csrf
def fbv(request):
if request.method == 'POST':
return HttpResponse('我是FBV!!!!')
return render(request, 'fbv.html')
-------------------------------------------------
CBV
'''针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法'''
方式1
html
<form action="http://127.0.0.1:8000/fbv/" method="post">
<input type="submit">
</form>
views
from django.utils.decorators import method_decorator
class MyFbv(views.View):
def get(self, request):
return HttpResponse('I From GET!!!')
@method_decorator(csrf_protect) # 加上Csfr验证
def post(self, request):
return HttpResponse('I Form POST!!!')
方式2
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect, name='post') # 指定对象
class MyFbv(views.View):
def get(self, request):
return HttpResponse('I From GET!!!')
def post(self, request):
return HttpResponse('I Form POST!!!')
方式3
from django.utils.decorators import method_decorator
class MyFbv(views.View): # 通过影响类中的dispatch方法添加一个csfr方法
@method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
super(MyFbv, self).dispatch(request, *args, **kwargs)
def get(self, request):
return HttpResponse('I From GET!!!')
def post(self, request):
return HttpResponse('I Form POST!!!')
'''针对CBV中的csrf_exempt只有方式3有效 针对其他装饰器上述三种方式都有效'''
四、Auth模块简介
我们都知道在Django中有自带的一个接口 那就是Admin的接口 但是我们没有账号密码 那就体验不到管理员的强大功能了
但是我们在做数据库迁移命令的时候发现有创建了10多张表格 其中有一张表格名字叫做Auth_user
这个表格就是专门用来配合Auth模块做用户的注册、登录、修改密码、注销....等等很多功能 该表是Django admin后台管理默认的表
Django 后台管理员账号创建需要到pycharm中的终端
python3 manage.py createsuperuser
五、Auth_user模块常见方法
'''判断当前用户有没有登录操作'''
html
<form method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
views
def login(request):
print(request.user)
'''
用户登录成功之后执行Auth.login 该方法返回当前登录用户对象 admin
用户没有登录成功没有执行Auth.login 该方法返回匿名用户对象 AnonymousUser
'''
print(request.user.is_authenticated) # 判断当前用户是否登录 返回True False
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 现在遇到一个问题就是怎么通过models.的方式去操作auth_user表格呢? 这个时候就有auth模块了
res = auth.authenticate(request, username=username, password=password)
# print(res.username, res.password,
# res.pk) # admin pbkdf2_sha256$150000$4NZp3wuIgf9A$7hfw7pcm35QosjTRWFpj9U3F5SoGTRqUv/H8DpBp308= 2
'''数据正确的情况下会有一个返回值是数据对象 数据错误的情况下返回的是None'''
if res:
auth.login(request, res) # 自动操作Cookie与Session
return render(request, 'login.html')
'''
用户登录装饰器
当用户没有登录的情况下跳转到注册界面 在settings文件中设置跳转的页面地址 LOGIN_URL = '/login/'
'''
from django.contrib.auth.decorators import login_required
@login_required
def index(request):
return HttpResponse('Form index view')
@login_required
def func(request):
return HttpResponse('Form func view')
'''重置密码'''
views
@login_required
def set_password(request):
if request.method == 'POST':
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
'''校验原密码是否正确 自定加密并检验'''
is_right = request.user.check_password(old_password)
if is_right:
request.user.set_password(new_password) # 修改密码
request.user.save() # 保存数据
return render(request, 'set_password.html')
html
<form action="" method="post">
{% csrf_token %}
<p>old_password:<input type="text" name=""></p>
<p>new_password:<input type="text" name=""></p>
<input type="submit">
</form>
'''自动清除Cookie与Session'''
views
@login_required
def loginout(request):
auth.logout(request) # 自动清楚cookie和Session
return HttpResponse('清除成功!!!')
'''创建用户'''
views
from django.contrib.auth.models import User
def register(request):
User.objects.create(username='Like', password=123, email='120@qq.com') # 这里创建的是普通用户 不能登录管理员系统
return HttpResponse('注册成功!!!')
六、Auth_user表切换
当我们使用管理员账户的时候发现字段不够管理员信息不够多 这个时候我们也没有办法添加字段
所以就有了表切换的方法自定义一张表然后继承之前管理员表
1.models
from django.contrib.auth.models import AbstractUser
'''主要是用来拓展Auth_user中没有的字段'''
class Userinfo(AbstractUser): # 继承原管理员表格
phone = models.BigIntegerField() # 可以随意添加
desc = models.TextField()
2.settings.py
AUTH_USER_MODEL = 'app01.Userinfo'
七、基于django中间件设计项目功能
'''简单的函数式封装 配置文件拔插式设计'''
应用app.py
class Dingding(object):
def __init__(self):
pass
def send(self, content):
print('DingDing消息通知', content)
settings
NOTIFY_FUNC_LIST = [
'notifys.notify.qq.Qq',
'notifys.notify.wechat.Weixin',
'notifys.notify.dingding.Dingding',
]
__init__
import importlib
import settings
def send_all(content):
for i in settings.NOTIFY_FUNC_LIST:
module_path, class_str_name = i.rsplit('.', maxsplit=1)
module = importlib.import_module(module_path)
class_name = getattr(module, class_str_name)
obj = class_name()
obj.send(content)
start
from notifys import notify
if __name__ == '__main__':
notify.send_all('国庆节要来啦!!!')
'''这个时候如果想让谁接收不到消息 注释掉即可 添加则是新建一个即可'''
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点点赞收藏+关注
谢谢支持 !!!