django10/csrf/auth

CSRF跨站请求伪造

CSRF操作

CSRF相关装饰器

auth认证模块

auth_user表切换

基于django中间设计项目功能

1.跨站请求伪造(CSRF)

什么是CSRF?、

Cross site Request Forgery 跨站请求伪造,是一种网络的攻击方式,它在2007年曾被列为互联网20大安全隐患之一,也被称为"One Click Attack " 或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,尽管听起来像跨站脚本(xss),但是它与XSS攻击相左,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求利用受信任的网站,与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比xss更具有危险性

image

CRSF模拟

1.简介
	钓鱼网站:假设是一个跟银行一模一样的网址页面,用户在该页面上转账,用户的账户钱少了,但是转账的地址出了问题。
2.模拟
	一台计算机两个服务端不同端口启动,钓鱼网站提交地址改为正规网站的地址
3.预防
	csrf策略: 通过返回的页面上添加独一无二的标识信息,从而区分正规网站和钓鱼网站

CSRF简单代码操作演示

演示要求

1.创建两个django项目,一个模仿正常网站A,一个是钓鱼网站B

2.两个网站前端展示一样

3.测试


正常网站A代码

视图层 views.py

from django.shortcuts import render

# Create your views here.

def transfer(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,'transfer.html')

路由层 url.py

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('transfer/',views.transfer)
]

模板层

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" 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">
        <input type="submit">
    </p>
</form>

</body>
</html>

钓鱼网站B

视图层 views.py

from django.shortcuts import render

# Create your views here.
def transfer(request):
    return render(request, 'transfer.html')

路由层、

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('transfer/',views.transfer)
]

模板层

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" 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">
        <input type="submit">
    </p>
</form>

</body>
</html>

效果展示:#钓鱼网站中,输入的目标账户其实是不存在的,已经指定写好了,周瑜的属性值已经被隐藏了。所以转账的时候默认转账给周瑜/


image

2.jango项目post请求提交403 [CSRF机制开启]

参考 Django csrf

如何处理抵御区别跨伪造站点攻击
开启csrf机制;
非真正的客户端的post请求一律转为403.
真正的客户端如何通过后端的校验呢,参考以下

真正的客户端如何通过CSRF机制请求呢?

1.form表单如何通过csrf机制?

image

2.ajax表单如何通过csrf机制?

image

方式1.form表单
	<form action="" method="post">
    	{% csrf_token %}
	</form>
----------------------------------------------------------------------------------------------------
方式2.ajax
	方式1:先编写csrf模板语法 然后利用标签查找和值获取 手动添加
      'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
	方式2:直接利用模板语法即可
      'csrfmiddlewaretoken':'{{ csrf_token }}'
------------------------------------------------------------------------------------------------
 方式3:通用方式(js脚本)
    	扩展性最高
详解方式一

{% csrf_token %} 在form表单中,添加此代码

如果前后端分离不推荐使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是真正的网站</h1>

<form action="" 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">
        <input type="submit">
        
    </p>
</form>
</body>
</html>
详解方式二

ajax语法 也会报403错误

{% csrf_token %} 不能少哦

方式1:先编写csrf模板语法 然后利用标签查找和值获取 手动添加
  'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
方式2:直接利用模板语法即可
  'csrfmiddlewaretoken':'{{ csrf_token }}'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是真正的网站</h1>
{% csrf_token %}
<button id="d1">奥巴马点击ajax请求查看</button>
<script>
    $('#d1').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {'username': 'jason', 'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()},
            success: function (args) {
            }
        })
    })
</script>
</form>
</body>
</html>
-------------------------------------- 【 'csrfmiddlewaretoken':'{{ csrf_token }}'】----------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是真正的网站</h1>
{% csrf_token %}
<button id="d1">奥巴马再次点击ajax请求查看</button>
<script>
    $('#d1').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {'username': 'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
            success: function (args) {
            }
        })
    })
</script>
</form>
</body>
</html>
详解方式三

通用性扩展性强

1.创建一个static文件夹

1.自己创建一个js脚本,放置在static中方便管理,每次使用调用即可。

csrf.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);
    }
  }
});

前端html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>这是真正的网站</h1>
<button id="d1">ajax查看</button>
<script src="/app01/static/csrf.js"></script>
<script>
    $('#d1').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data:{'username':'jason'},
            success: function (args) {
            }
        })
    })
</script>
</form>
</body>
</html>

3.CSRF相关装饰器

django中,settings中的这项csrf机制('django.middleware.csrf.CsrfViewMiddleware',)配置是全局的,要么全局校验,要么不校验,我们想局部校验如何呢?想那块校验就那块校验能否办到?

FBV

from django.views.decorators.csrf import csrf_protect,csrf_exempt
1.当整个网站默认都不校验csrf 但是局部视图函数需要校验 如何处理
-----------------------------------------------------------------------------
@csrf_protect
def home(request):
    return HttpResponse('哈哈哈')
    
2.当整个网站默认都校验csrf 但是局部视图函数不需要校验 如何处理
--------------------------------------------------------------------------
@csrf_exempt
def home(request):
    return HttpResponse('哈哈哈')

CBV

针对csrf_exempt只有方式3有效 针对其他装饰器上述三种方式都有效

针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法
#@method_decorator(csrf_protect, name='post')  # 方式2:指名道姓的添加
class MyHome(views.View):
    #@method_decorator(csrf_protect)  # 方式3:影响类中所有的方法
    def dispatch(self, request, *args, **kwargs):
        super(MyHome, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return HttpResponse('Home Get view')

    # @method_decorator(csrf_protect)  # 方式1:指名道姓的添加
    def post(self, request):
        return HttpResponse('Home Post view')

auth模块

auth模块是什么?

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

django执行数据库迁移命令之后会产生一个auth_user表
	该表可以配合auth模块做用户相关的功能:注册 登录 修改密码 注销 ...
 	该表还是django admin后台管理默认的表
 		django admin后台管理员账号创建 
        	python manage.py createsuperuser

2.auth模块常用方法

auth认证模块


我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

django自带的admin后台管理用户登录参考的就是auth_user表。

创建admin后台管理员用户
tools---run manage.py task---执行createsuperuser
自动对用户密码进行加密处理并保存

auth模块方法大全

1.验证用户名和密码是否正确

auth.authenticate() # 校验正确返回的是用户对象 错误返回的是None

2.保存用户登录状态

auth.login() # 自动帮你操作session相关

3.获取当前用户对象

request.user # 获取当前登录的用户对象 或者是 匿名用户

4.判断当前用户是否登录

request.user.is_authenticated()  # 判断用户是否登录 返回布尔值

5.校验登录装饰器

from django.contrib.auth.decorators import login_required
@login_required(login_url='/lg/')  # 局部配置
@login_required  # 全局配置
LOGIN_URL = '/lg/'  # 需要在配置文件中添加配置

6.修改密码

request.user.check_password() # 自动加密再比对
request.user.set_password()  # 临时修改密码
request.user.save()  # 将修改操作同步到数据库中

7.注销登录

auth.logout(request)

8.注册用户

from django.contrib.auth.models import User
User.objects.create_superuser(username='admin',password='123',email='123@qq.com')  # 管理员
User.objects.create_user(username='oscar',password='123')  # 普通用户

auth扩展表字段


方式1:编写一对一表关系(了解)

方式2:类继承(推荐)

# settings
'''告诉auth模块 不再使用auth_user 而是使用自定义的表'''
AUTH_USER_MODEL = 'app01.Users'

# models
from django.contrib.auth.models import AbstractUser
class Users(AbstractUser):
    # 编写AbstractUser类中没有的字段 不能冲突!!!
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)

注意:

  1. 类继承之后,需要重新执行数据库迁移命令,并且库里面是第一次操作才可以
  2. auth模块所有的方法都可以直接在自定义模型类上面使用,自动切换参照表

代码:

def login(request):
    print(request.user)
    """
    当用户登录成功之后(执行了auth.login) 该方法返回当前登录用户对象
    当用户没有登录成功(没有执行auth.login) 该方法返回匿名用户对象
    """
    print(request.user.is_authenticated)  # 判读当前用户是否登录
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 查询数据库校验数据(密码自动加密再比对)
        is_user_obj = auth.authenticate(request,username=username,password=password)
        '''
        数据正确的情况下返回的是数据对象
        数据错误的情况下返回的是None
        '''
        if is_user_obj:
            auth.login(request,is_user_obj)  # 自动操作cookie和session
    return render(request, 'login.html')

# @login_required(login_url='/login/')  # 校验用户是否登录 默认跳转的登录地址比较复杂 我们可以自定义跳转的登录地址
@login_required
def index(request):
    return HttpResponse('index view')

# @login_required(login_url='/login/')  # 局部配置 每次都需要自己写 量大的情况下不方便
@login_required
def func(request):
    return HttpResponse('func view')


@login_required
def set_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        # 1.校验原密码是否正确
        is_right = request.user.check_password(old_password)  # 自动加密并校验
        if is_right:
            # 2.修改密码
            request.user.set_password(new_password)
            # 3.保存数据
            request.user.save()
    return render(request,'set_password.html')


@login_required
def logout(request):
    auth.logout(request)  # 自动清除cookie和session
    return HttpResponse('注销')

from django.contrib.auth.models import User
def register(request):
    # User.objects.create(username='jason',password=123)  # 不能使用(密码不加密)
    # User.objects.create_user(username='jason',password=123)  # 创建普通用户
    User.objects.create_superuser(username='tony',password=321,email='666@qq.com')
    return HttpResponse('注册功能')
posted @ 2022-09-13 22:15  名字长的像一只老山羊  阅读(17)  评论(0编辑  收藏  举报