csrf(跨站請求偽造)
django通過中間件 django.middleware.csrf.CsrfViewMiddleware?為用戶實現(xiàn)防止跨站請求偽造的功能沪饺。
原理:在用戶訪問django的可信站點時姊途,django在用戶表單中生成一個隱含字段(csrftoken),值是在服務器端隨機生成的术浪,
當用戶提交表單時亿鲜,服務器通過檢驗表單的 csrftoken值是否和自己保存的一致,來判斷用戶的合法性搬瑰。
源碼分析:
CsrfViewMiddleware類的 process_request() 方法首先從配置文件獲取 ????CSRF_USE_SESSIONS的值涩金,如果有值從session獲取 CSRF_SESSION_KEY的值并返回
如果沒有從請求的COOKIE中獲取 CSRF_COOKIE_NAME的值,沒有返回 None漱牵。
# process_request() 代碼片段
def process_request(self, request):
? ? ? ? csrf_token = self._get_token(request)
? ? ? ? if csrf_token is not None:
? ? ? ? ? ? request.META['CSRF_COOKIE'] = csrf_token
? ? def _get_token(self, request):
? ? ? ? if settings.CSRF_USE_SESSIONS:
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? return request.session.get(CSRF_SESSION_KEY)
? ? ? ? ? ? except AttributeError:
? ? ? ? ? ? ? ? raise ImproperlyConfigured(
? ? ? ? ? ? ? ? ? ? 'CSRF_USE_SESSIONS is enabled, but request.session is not '
? ? ? ? ? ? ? ? ? ? 'set. SessionMiddleware must appear before CsrfViewMiddleware '
? ? ? ? ? ? ? ? ? ? 'in MIDDLEWARE%s.' % ('_CLASSES' if settings.MIDDLEWARE is None else '')
? ? ? ? ? ? ? ? )
? ? ? ? else:
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME]
? ? ? ? ? ? except KeyError:
? ? ? ? ? ? ? ? return None
? ? ? ? ? ? csrf_token = _sanitize_token(cookie_token)
? ? ? ? ? ? if csrf_token != cookie_token:
? ? ? ? ? ? ? ? request.csrf_cookie_needs_reset = True
? ? ? ? ? ? return csrf_token
CsrfViewMiddleware process_view() 方法首先檢查函數(shù)是否被 csrf_exempt裝飾器裝飾夺蛇,如果被裝飾則返回 None,
如果沒被裝飾則從請求頭中取出 CSRF_COOKIE值,與表單中的 csrfmiddlewaretoken的值進行校驗酣胀,
校驗通過程序接著執(zhí)行刁赦,否則返回 403 Forbidden錯誤。
# process_view() 代碼片段
? ? def process_view(self, request, callback, callback_args, callback_kwargs):
? ? ? ? if getattr(request, 'csrf_processing_done', False):
? ? ? ? ? ? return None
? ? ? ? if getattr(callback, 'csrf_exempt', False):
? ? ? ? ? ? return None
? ? ? ? ? ? csrf_token = request.META.get('CSRF_COOKIE')
? ? ? ? ? ? if csrf_token is None:
? ? ? ? ? ? ? ? return self._reject(request, REASON_NO_CSRF_COOKIE)
? ? ? ? ? ? request_csrf_token = ""
? ? ? ? ? ? if request.method == "POST":
? ? ? ? ? ? ? ? try:
? ? ? ? ? ? ? ? ? ? request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
? ? ? ? ? ? ? ? except IOError:
? ? ? ? ? ? ? ? ? ? pass
? ? ? ? ? ? if request_csrf_token == "":
? ? ? ? ? ? ? ? request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
? ? ? ? ? ? request_csrf_token = _sanitize_token(request_csrf_token)
? ? ? ? ? ? if not _compare_salted_tokens(request_csrf_token, csrf_token):
? ? ? ? ? ? ? ? return self._reject(request, REASON_BAD_TOKEN)
? ? ? ? return self._accept(request)
實現(xiàn)django防止跨站請求偽造方式:
在django的settings配置文件中 MIDDLEWARE 列表中添加 'django.middleware.csrf.CsrfViewMiddleware' 中間件闻镶,此方式會在全局進行csrf驗證甚脉,
如果某個視圖函數(shù)或者類不進行驗證,可以通過 csrf_exempt裝飾器實現(xiàn)
? ? 示例:
????from django.views.decorators.csrf import csrf_exempt
????@csrf_exempt?
?????def index(request):
????????????pass
也可以把csrf_exempt裝飾器直接加在URL路由映射中铆农,使某個視圖函數(shù)不經(jīng)過CSRF驗證
示例:
?from django.views.decorators.csrf import csrf_exempt
from app import views
url(r'^index/',csrf_exempt(views.index)),
如果沒有在django項目的settings文件中沒有設置?'django.middleware.csrf.CsrfViewMiddleware' 中間件牺氨,可以通過?csrf_protect裝飾器實現(xiàn) CSRF驗證
示例:
from django.views.decorators.csrf import csrf_protect
@csrf_protect?
def index(request):?
????????pass
或者
from django.views.decorators.csrf import csrf_protect
url(r'^index/',csrf_protect(views.index)),