Pythonの開発者[ジャンゴ]:ミドルウェア、CSRF
CSRF
1.概要
ユーザーがサイトにログオンしている場合CSRF(クロスサイトリクエストフォージェリ)、クロスサイトリクエストフォージェリは、という点で、たとえば、あなたのサイトへのリンクがあり、その後、ユーザーが悪質なWebサイトをクリックしたときにその悪意のあるWebサイト上のリンクは、要求をあなたのサイトに送信されますと、あなたのサイトは、この要求は、ユーザ自身に送信されると思いますが、実際には、この要求は、悪質な偽のウェブサイトということです。
このような状況を避けるために、DjangoのCSRF保護メカニズムを引用し、Djangoのクライアントからの要求に最初の応答、それがランダムにサーバ側でトークンを生成し、クッキーにトークンを配置します。POSTリクエストがあることCSRF攻撃を避けるために、各時間は、トークンをもたらすでしょうです。何のPOSTリクエストトークンランダムな文字列が存在しない場合は、サービス403の否定を返します。
- クッキーHTTPレスポンスが内側に戻って、Djangoはその値が自動的にトークンによって生成され、あなたのためのcsrftokenフィールドを追加します
- POSTフォームの全てが、csrfmiddlewaretokenフィールドを含まなければならない場合には(リガで唯一のテンプレートタグ、Djangoは自動的に以下を参照してください、生成するのに役立ちます)
- 値とPOSTリクエストが処理される前にcsrfmiddlewaretokenフィールドの形で提出され、Djangoは同じかどうか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.概要
Djangoのミドルウェア(ミドルウェア)で、ジャンゴで、ミドルウェアは、実際のクラスであり、リクエストの到着後、メソッドに対応するDjangoのミドルウェアは、独自のルールに従って適切なタイミングで実行され、Djangoのプロジェクトの設定次のようにモジュールは、各要素が中間であることを特徴とする請求変数ミドルウェアは、次のとおりです。
`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'``,``]`
4つのメソッドを定義することができますミドルウェアは以下のとおりです。
- process一スキップが行われ、次の中間書き込まれていない実行要求に(自己、リクエスト);戻りHttpResonseは、以下の中間体は実行されない場合
- process_view(自己、要求、コールバック、callback_args、callback_kwargs)実施後process一最初のインプリメンテーション、実行から再び始まるproces_view
- process_template_response(自己、リクエスト、レスポンス)オブジェクトは、メソッドをレンダリング有する機能のビューに返された場合、このメソッドが実行されます
- process_exception(自己、要求、例外)場合、機能実行エラーviews.py、異常トリガを行う、この方法が実行され、エラーが発生した場合、最も優先順位の高い例外の最低レベル、最近実行、および実行方法respnseを
- process_response(自己、リクエスト、レスポンス)をスキップを行う、次の中間書き込まれていない実行要求を返し、戻りHttpResonseは、元のデータを置き換える場合
それなしではない場合、上記のメソッドの戻り値なしHttpResonseオブジェクトは、オブジェクトはユーザーに直接戻された場合、次に、ルールに従って定義ジャンゴダウン続け、HttpResonseオブジェクトでないとすることができます
注意:Djangoのバージョン1.10の後に直接実行process_responseのと同じレベルではなく、最低process_responseから開始
2、カスタムミドルウェア
Djangoのホームディレクトリの下に(任意の名前を付ける)ディレクトリミドルウェアを作成し、ディレクトリm.pyでファイルを作成します
①process一、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