파이썬 개발자 [장고] : 미들웨어, CSRF
CSRF
1. 개요
사용자가 사이트에 로그온 할 경우 CSRF (크로스 사이트 요청 위조) 크로스 사이트 요청 위조는 측면에서, 예를 들어, 귀하의 사이트에 대한 링크가, 다음 사용자가 악의적 인 웹 사이트를 클릭 할 때 악의적 인 웹 사이트에 대한 링크가, 요청이 사이트로 전송됩니다 때, 귀하의 사이트는이 요청을 사용자 고유의, 실제로,이 요청은 그 악의적 인 가짜 웹 사이트로 전송하고 있다고 생각합니다.
위의 상황을 피하려면, 장고 CSRF 보호 메커니즘을 인용, 클라이언트의 요청에 대한 첫 번째 응답, 그것은 무작위로 서버 측에서 토큰을 생성하고, 쿠키에 토큰을 넣어 것 장고 때. POST 요청되는 CSRF 공격을 피하기 위해 각 시간이 토큰을 가져올 것입니다. 더 POST 요청 토큰 임의의 문자열이없는 경우, 서비스 (403)의 거부를 반환
- 쿠키 HTTP 응답이 내부 반환에서, 장고는 값이 자동으로 토큰에 의해 생성되는, 당신을 위해 csrftoken 필드를 추가합니다
- POST가 양식을 모두하는 csrfmiddlewaretoken 필드를 포함해야합니다 때 (리가 하나 개의 템플릿 태그, 장고가 자동으로 아래 참조, 생성하는 데 도움이됩니다)
- 값과 POST 요구가 처리되기 전에 csrfmiddlewaretoken 필드의 형태로 제출은 장고 동일 여부 csrftoken 분야에서 과자의 요청을 확인한다. 그것은이 그렇지 않으면, 합법적 인 요청을 나타냅니다으로, 요청이 다른 사람의 CSRF 공격에서 올 수있는 경우, 고궁 (403)를 반환합니다.
- X-CSRFTOKEN 헤더 값이 쿠키의 값을 모두 추가 AJAX POST 요청에 csrftoken되고
이제 우리는 settings.py에서 미들웨어 django.middleware.csrf.CsrfViewMiddleware를 활성화해야합니다 :
`MIDDLEWARE ``=` `[`` ``'django.middleware.csrf.CsrfViewMiddleware'``,``]`
지역 사용하기 :
- @csrf_protect, 설정이 전체 미들웨어를 설정되지 않은 경우에도, 현재 함수 CSRF 방지 기능에 강요했다.
- @csrf_exempt, 글로벌 설정이 미들웨어에 설정 한 경우에도, 현재 함수의 CSRF 방지 기능을 취소합니다.
사용 CBA :
`from` `django.utils.decorators ``import` `method_decorator``class` `AssetView(View):`` ``@method_decorator``(csrf_exempt) ``#必须加到dispatch上,get、post上都不好使`` ``def` `dispatch(``self``, request, ``*``args, ``*``*``kwargs):`` ``return` `super``(AssetView, ``self``).dispatch(request, ``*``args, ``*``*``kwargs)`
(2) 폼 POST 요청 양식 제출
파일 :
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def login(request):
if request.method == 'GET':
return render(request,'login.html')
elif request.method == 'POST':
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'root' and pwd == "123":
# 生成随机字符串
# 写到用户浏览器Cookie
# 保存到Session中
# 在随机字符串对应的字典中设置相关内容...
request.session['username'] = user
request.session['if_login'] = True #可不加 直接判断username也可以
if request.POST.get('session') == '1': #单独设置超时时间,当前session生效,不影响全局
request.session.set_expiry(10) #10秒
return redirect('/index/')
else:
return redirect('/login/')
def index(request):
# 获取当前用户的随机字符串
# 根据随机字符串获取对应信息
if request.session.get('if_login'):
return render(request, 'index.html')
else:
return redirect('/login/')
login.html 파일 :
`{``# 添加{% csrf_token %} #}``<!DOCTYPE html>``<html lang``=``"en"``>``<head>`` ``<meta charset``=``"UTF-8"``>`` ``<title>Title<``/``title>``<``/``head>``<body>`` ``<form action``=``"/login/"` `method``=``"post"``>`` ``{``%` `csrf_token ``%``}`` ``<``input` `type``=``"text"` `name``=``"user"` `/``>`` ``<``input` `type``=``"text"` `name``=``"pwd"` `/``>`` ``<``input` `type``=``"checkbox"` `name``=``"session"` `value``=``"1"``/``> 保存``1``个月`` ``<``input` `type``=``"submit"` `value``=``"提交"` `/``>`` ``<``/``form>``<``/``body>``<``/``html>`
3, 아약스는 POST 요청을 제출
파일 :
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def login(request):
if request.method == 'GET':
return render(request,'login.html')
elif request.method == 'POST':
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'root' and pwd == "123":
# 生成随机字符串
# 写到用户浏览器Cookie
# 保存到Session中
# 在随机字符串对应的字典中设置相关内容...
request.session['username'] = user
request.session['if_login'] = True #可不加 直接判断username也可以
if request.POST.get('session') == '1': #单独设置超时时间,当前session生效,不影响全局
request.session.set_expiry(10) #10秒
return redirect('/index/')
else:
return redirect('/login/')
def index(request):
# 获取当前用户的随机字符串
# 根据随机字符串获取对应信息
if request.session.get('if_login'):
return render(request, 'index.html')
else:
return redirect('/login/')
login.html 파일 :
`{``# Ajax提交时要添加headers值 #}``<!DOCTYPE html>``<html lang``=``"en"``>``<head>`` ``<meta charset``=``"UTF-8"``>`` ``<title>Title<``/``title>``<``/``head>``<body>`` ``<form action``=``"/login/"` `method``=``"post"``>`` ``{``%` `csrf_token ``%``} `` ``<``input` `type``=``"text"` `name``=``"user"` `/``>`` ``<``input` `type``=``"text"` `name``=``"pwd"` `/``>`` ``<``input` `type``=``"checkbox"` `name``=``"session"` `value``=``"1"``/``> 保存``1``个月`` ``<``input` `id``=``'btn'` `type``=``"button"` `value``=``"Ajax提交"` `/``>`` ``<``/``form>`` ``<script src``=``"/static/jquery-1.12.4.js"``><``/``script>`` ``<script src``=``"/static/jquery.cookie.js"``><``/``script>`` ``<script>`` ``$(function () {`` ``$(``'#btn'``).click(function () {`` ``$.ajax({`` ``url:``'/login/'``,`` ``type``:``'POST'``,`` ``data:{``'user'``:``'root'``,``'pwd'``:``'123'``},`` ``headers:{``'X-CSRFtoken'``:$.cookie(``'csrftoken'``)},`` ``success:function (arg) {`` ``}`` ``})`` ``})`` ``})`` ``<``/``script>``<``/``body>``<``/``html>`
위의 HTML 파일 후, 제출 성공적인 실행을 클릭합니다,하지만 종종 프로그램은 Ajax 요청보다 더 많은, 그래서 우리 모두는 각 요청에 대해 헤더 Ajax 요청 헤더를 추가해야 할 일이 너무 너무 엄청난 양의 다음, 당신은 모든이없는, 전역 설정을 할 필요가 요청 헤더 추가
{# Ajax提交时全局生效 #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
{% csrf_token %}
<input type="text" name="user" />
<input type="text" name="pwd" />
<input type="checkbox" name="session" value="1"/> 保存1个月
<input id='btn' type="button" value="Ajax提交" />
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$(function () {
{# 全局配置,所有Ajax请求都先执行下面操作#}
$.ajaxSetup({
beforeSend:function (xhr,settings) {
xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
}
});
$('#btn').click(function () {
$.ajax({
url:'/login/',
type:'POST',
data:{'user':'root','pwd':'123'},
success:function (arg) {
}
})
})
})
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% csrf_token %}
<input type="button" onclick="Do();" value="Do it"/>
<script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
<script src="/static/plugin/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
var csrftoken = $.cookie('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);
}
}
});
function Do(){
$.ajax({
url:"/app01/test/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
});
}
</script>
</body>
</html>
미들웨어
1. 개요
장고 미들웨어 (미들웨어)에서는, 장고 미들웨어 실제로 클래스이고, 상기 요청의 도착 후에있어서 해당 장고 미들웨어는 자신의 규칙에 따라 적절한 시간에 실행된다; 장고 프로젝트 설정 다음 모듈의 각 요소가 중간이고 변수 미들웨어이다 :
`MIDDLEWARE ``=` `[`` ``'django.middleware.security.SecurityMiddleware'``,`` ``'django.contrib.sessions.middleware.SessionMiddleware'``,`` ``'django.middleware.common.CommonMiddleware'``,`` ``'django.middleware.csrf.CsrfViewMiddleware'``,`` ``'django.contrib.auth.middleware.AuthenticationMiddleware'``,`` ``'django.contrib.messages.middleware.MessageMiddleware'``,`` ``'django.middleware.clickjacking.XFrameOptionsMiddleware'``,``]`
네 가지 방법을 정의 할 수 있습니다 미들웨어는 다음과 같습니다
- process_request 스킵을 수행하는 다음의 중간 기록되지 실행 요청 (자기 요청), 리턴 HttpResonse,하기 중간체가 실행되지 않을 때
- process_view (자기, 요청 콜백 callback_args, callback_kwargs) 개시 후 process_request 제 구현, 실행부터 다시 시작 proces_view
- 객체가 렌더링 메소드를 갖는 함수 뷰에 반환되는 경우 process_template_response (자기, 요청 응답),이 방법을 수행
- process_exception 기능 실행 오류 views.py은이 방법이 수행된다 (자동 요청 예외) 이상 수행 트리거; 에러는 최고 우선 순위 예외의 최저 레벨, 최근의 실행 및 실행 방법 respnse 발생시
- process_response (자기, 요청 응답) 스킵을 수행하는 다음의 중간 기록되지 실행 요구를 반환 복귀 HttpResonse는, 원래의 데이터와 교체
그 중에없는 경우, 상기 방법의 반환 값 없음 HttpResonse 객체는 객체가 사용자에게 직접 반환되는 경우 다음의 규칙에 따라 정의 장고 속행, HttpResonse 개체 없을 수 있고
참고 : 장고 버전 1.10 이후 직접 실행 process_response 동일한 수준의 대신 가장 낮은 process_response에서 시작
2, 사용자 정의 미들웨어
장고의 홈 디렉토리 아래에 디렉토리 미들웨어 (모든 이름) 만들기 디렉토리 m.py에서 파일을 생성
① process_request, process_response
파일의 사용자 정의 미들웨어 클래스 :
`from` `django.utils.deprecation ``import` `MiddlewareMixin``from` `django.shortcuts ``import` `HttpResponse` `class` `Row1(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森1"``)`` ``# return HttpResponse("DDDD")`` ``def` `process_response(``self``,request,response):`` ``print``(``"扛把子1"``)`` ``return` `response` `class` `Row2(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森2"``)`` ``def` `process_response(``self``, request, response):`` ``print``(``"扛把子3"``)`` ``return` `response` `class` `Row3(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森3"``)`` ``def` `process_response(``self``, request, response):`` ``print``(``"扛把子3"``)`` ``return` `response`
미들웨어 설정 파일을 로그인 :
`from` `django.middleware.csrf ``import` `CsrfViewMiddleware``MIDDLEWARE ``=` `[`` ``'django.middleware.security.SecurityMiddleware'``,`` ``'django.contrib.sessions.middleware.SessionMiddleware'``,`` ``'django.middleware.common.CommonMiddleware'``,`` ``'django.middleware.csrf.CsrfViewMiddleware'``,`` ``'django.contrib.auth.middleware.AuthenticationMiddleware'``,`` ``'django.contrib.messages.middleware.MessageMiddleware'``,`` ``'django.middleware.clickjacking.XFrameOptionsMiddleware'``,`` ``'middleware.m.Row1'``,`` ``'middleware.m.Row2'``,`` ``'middleware.m.Row3'``,`
인쇄가 수행됩니다
王森1
王森2
王森3
走你
扛把子3
扛把子3
扛把子1
② process_view
파일의 사용자 정의 미들웨어 클래스 :
`from` `django.utils.deprecation ``import` `MiddlewareMixin``from` `django.shortcuts ``import` `HttpResponse` `class` `Row1(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森1"``)`` ``def` `process_view(``self``, request, view_func, view_func_args, view_func_kwargs):`` ``print``(``"James1"``)`` ``def` `process_response(``self``,request,response):`` ``print``(``"扛把子1"``)`` ``return` `response` `class` `Row2(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森2"``)`` ``def` `process_view(``self``, request, view_func, view_func_args, view_func_kwargs):`` ``print``(``"James2"``)`` ``def` `process_response(``self``, request, response):`` ``print``(``"扛把子3"``)`` ``return` `response` `class` `Row3(MiddlewareMixin):`` ``def` `process_request(``self``,request):`` ``print``(``"王森3"``)`` ``def` `process_view(``self``, request, view_func, view_func_args, view_func_kwargs):`` ``print``(``"James3"``)`` ``def` `process_response(``self``, request, response):`` ``print``(``"扛把子3"``)`` ``return` `response`
인쇄가 수행됩니다
王森1
王森2
王森3
James1
James2
James3
走你
扛把子3
扛把子3
扛把子1