148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击
2021-06-03 18:05
阅读:706
YPE html>
标签:很多 jquery 更新 baidu pos 不能 _id 判断 发送请求
CSRF攻击概述:
CSRF(Cross Site Request Forgery 跨站域请求伪造)是一种网站攻击的方式,它在2007年曾被列为互联网20大安全隐患之一。其他的安全隐患,比如SQL脚本注入,跨站域脚本攻击等在近年来已经逐渐为众人熟知,很多网站也都针对他们进行了防御。然而,对于大多数人来说,CSRF还是很陌生的,Gmail在2007年底也存在csrf漏洞,从而被黑客攻击而使Gmail的用户造成巨大的损失。
CSRF攻击原理:
网站是通过cookie来实现登录功能的。而cookie只要存在浏览器中,那么浏览器在访问这个cookie的服务器的时候,就会自动的携带cookie信息到服务器上去。那么这个时候就存在一个漏洞了,如果你访问了一个病毒网站或者是别有用心的网站,这个网站可以在网页源代码中插入js代码,使用js代码给其他服务器发送请求(比如ICBC的转账请求)。那么因为在发送请求的时候,浏览器会自动的把cookie发送给对应的服务器,这时候相应的服务器(比如ICBC网站),就不知道这个请求是伪造的,从而就可以达到在用户不知情的情况下,给服务器发送一个请求(转账)。
防御CSRF攻击:
CSRF攻击的要点就是在向服务器发送请求的时候,相应的cookie会自动的发送给对应的服务器。造成服务器不知道这个请求的情况下是用户发起的还是伪造的。这时候,我们可以在用户每次访问有表单的页面的时候,在网页源代码中加入一个随机的字符串叫做csrf_token,在cookie中也加入一个相同值的csrf_token字符串。以后给服务器发送请求的时候,必须在body中以及在cookie中都携带csrf_token,服务器只有检测到cookie中的csrf_token和body中csrf_token都相同,才认为这个请求是合法的。
实例
比如,我们要实现一个icbc网站注册、登录、退出登录、转账的功能。
(1)views.py文件中示例代码如下:
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
from django.views import View
from .models import User
from .forms import SignupForm, SigninForm, TransferForm
from django.contrib import messages
from django.db.models import F
def index(request):
return render(request,'index.html')
class SignupView(View):
def get(self, request):
return render(request, 'signup.html')
def post(self, request):
form = SignupForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse('signin'))
else:
print(form.errors.get_json_data())
return redirect(reverse('signup'))
class SigninView(View):
def get(self, request):
return render(request,'signin.html')
def post(self, request):
form = SigninForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
user = User.objects.get(username=username, password=password, email=email)
if user:
request.session['user_id'] = user.pk
return redirect(reverse('transfer'))
else:
return redirect(reverse('signup'))
else:
print(form.errors.get_json_data())
return HttpResponse('请确定输入的信息是否正确!')
class TransferView(View):
def get(self,request):
return render(request, 'transfer.html')
def post(self, request):
form = TransferForm(request.POST)
context = {
'info': '转账成功!'
}
if form.is_valid():
email = form.cleaned_data.get('email')
money = form.cleaned_data.get('money')
user_id = request.session.get('user_id')
user = User.objects.filter(pk=user_id).first()
if user.balance >= money:
user.balance -= money
user.save()
User.objects.filter(email=email).update(balance=F('balance')+money)
return render(request, 'transfer.html', context={'context': context})
else:
return HttpResponse('余额不足!')
else:
print(form.errors.get_json_data())
return redirect(reverse('transfer'))
def Logout(request):
# 其实,调用flush()方法的时候,首先会将cookie中的session_id中的内容清空,并不会直接删除在cookie记录的session_id,
# 如果再次执行该函数就会将原来cookie中还保留的session_id 删除。
request.session.flush()
context = {
'info': '成功退出登录',
}
return render(request, 'index.html', context={'context': context})
(2)urls.py文件中进行视图函数与url之间的映射,示例代码如下:
from django.urls import path
from front import views
urlpatterns = [
path('', views.index, name='index'),
path('signup/', views.SignupView.as_view(), name='signup'),
path('signin/', views.SigninView.as_view(), name='signin'),
path('transfer/', views.TransferView.as_view(), name='transfer'),
path('logout/', views.Logout, name='logout'),
]
(3)index.html(中国工商银行首页)中示例代码如下:
ICBC
中国工商银行首页
- 登录
- 注册
- 退出登录
{{ context.info }}
(4)signup.html(注册界面)示例代码如下:
ICBC
中国工商银行注册界面
(5)signin.html(登录界面)示例代码如下:
ICBC
中国工商银行登录界面
(6)transfer.html(转账界面)示例代码如下:
ICBC
中国工商银行转账界面
{{ context.info }}
(7)User模型的定义,models.py文件中示例代码如下:
from django.db import models
from django.core import validators
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=24, validators=[validators.MinLengthValidator(6)])
email = models.EmailField()
balance = models.FloatField(default=0) # 余额
class Meta:
db_table = 'user'
(8)定义表单验证我们使用post请求提交的信息,forms.py文件中示例代码如下:
from .models import User
from django import forms
class SignupForm(forms.ModelForm):
password_repeat = forms.CharField(max_length=24, min_length=6)
class Meta:
model = User
fields = ['username', 'password','email']
def clean(self):
clean_data = super(SignupForm, self).clean()
password = clean_data.get('password')
password_repeat = clean_data.get('password_repeat')
if password != password_repeat:
raise forms.ValidationError('两次输入密码不一致!')
return clean_data
class SigninForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'password', 'email']
class TransferForm(forms.Form):
email = forms.CharField(max_length=30)
money = forms.FloatField()
==此时,该网站有一个小bug,就是在用户点击退出登录,或者是直接将浏览器中cookie中的session_id删除之后,同样可以访问转账的界面,这样的话,就有些不符合情理了。==
装饰器:实现没有登录不能访问转账的界面
(1)这个就可以使用装饰器来实现,自定义装饰器。可以在APP中创建一个python文件(decorators.py),定义装饰器函数,示例代码如下:
def login_decorator(func):
def wrapper(request, *args, **kwargs):
user_id = request.session.get('user_id')
exists = User.objects.filter(pk='user_id').exists()
if exists:
return func(request, *args, **kwargs)
else:
return redirect(reverse('signin'))
return wrapper
(2)在views.py中导入写好的装饰器,并且装饰到转账类视图上,示例代码如下:
from django.utils.decorators import method_decorator
from .decorators import login_decorator
@method_decorator(login_decorator, name='dispatch')
class TransferView(View):
def get(self,request):
return render(request, 'transfer.html')
def post(self, request):
form = TransferForm(request.POST)
context = {
'info': '转账成功!'
}
if form.is_valid():
email = form.cleaned_data.get('email')
money = form.cleaned_data.get('money')
user_id = request.session.get('user_id')
user = User.objects.filter(pk=user_id).first()
if user.balance >= money:
user.balance -= money
user.save()
User.objects.filter(email=email).update(balance=F('balance')+money)
return render(request, 'transfer.html', context={'context': context})
else:
return HttpResponse('余额不足!')
else:
print(form.errors.get_json_data())
return redirect(reverse('transfer'))
(3)之后,如果不登录就访问转账的界面http://127.0.0.1:8001/transfer/,就会重定向到登录的界面,不允许用户在未登录的情况下访问转账界面。
中间件优化ICBC网站
在我们以上的代码中,多次进行判断cookie的session中是否存在user_id,从数据库中查找与user_id相同的pk。所以,我们可以将这个直接定义为一个中间件,直接将这样的用户定义为front_user,并且绑定在request上。在APP中创建一个middlewares.py文件,用来存放自定义的中间件的函数,示例代码如下:
from .models import User
def front_user_middleware(get_response):
print('front_user_middleware初始化执行的代码....')
def middleware(request):
print("request到达view视图之前执行的代码....")
user_id = request.session.get('user_id')
if user_id:
try:
user = User.objects.get(pk=user_id)
request.front_user = user
except:
request.front_user = None
else:
request.front_user = None
response = get_response(request)
print('response到达浏览器之前执行的代码....')
return response
return middleware
之后,在项目的settings.py文件中的MIDDLEWARE添加我们自定义的中间件函数,规则为:appname.pythonfilename.functionname,front.middlewares.front_user_middleware。
IFrame相关知识
1. iframe可以加载嵌入别的域名下的网页。也就是说可以发送跨域请求。比如我可以在自己的网页中加载百度的网站,示例代码如下:
2.因为iframe加载的是别的域名下的网页,根据同源策略,js只能操作属于本域名下的代码,因此,js不能操作通过iframe加载来的DOM元素。
3.如果iframe的src属性为空,那么就没有同源策略的限制,这时候我们就可以操作iframe下面的代码了。并且,如果src为空,那么我们可以在iframe中,给任何域名发送请求。
4.直接在iframe中写html代码,浏览器并不会加载。因此,我们可以先让网页加载html代码,之后执行js代码将html加载进入iframe向指定的url发送请求。
比如,我们现在可以创建一个新的项目,实现js操作iframe向我们的icbc银行网站发送一个转账给孤烟逐云(333333@qq.com)100元的请求,只是实现一个首页。
(1)views.py文件中示例代码如下:
from django.shortcuts import render
def index(request):
return render(request, 'index.html')
(2)urls.py文件中进行视图函数与url之间的映射,示例代码如下:
from django.urls import path
from .import views
urlpatterns = [
path('', views.index, name='index'),
]
(3)index.html代码如下:
病毒网站
这个时候,如果我们登录的icbc网站转账的cookie中还保留有我们的信息,这个时候只要访问了我们定义的病毒网站的首页,我们登录的用户数据库中的余额就会少100元。当然了,进行这种csrf攻击的前提是我们在icbc网站的项目settings.py文件中没有开启中间件CsrfMiddleware。如果开启了该中间件,就不能进行这种csrf攻击了。
148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击
标签:很多 jquery 更新 baidu pos 不能 _id 判断 发送请求
原文地址:https://www.cnblogs.com/guyan-2020/p/12347200.html
文章来自:搜素材网的编程语言模块,转载请注明文章出处。
文章标题:148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击
文章链接:http://soscw.com/index.php/essay/90112.html
文章标题:148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击
文章链接:http://soscw.com/index.php/essay/90112.html
评论
亲,登录后才可以留言!