Code source de django.middleware.csrf

"""Cross Site Request Forgery Middleware.This module provides a middleware that implements protectionagainst request forgeries from other sites."""from__future__importunicode_literalsimportloggingimportrefromdjango.confimportsettingsfromdjango.core.urlresolversimportget_callablefromdjango.utils.cacheimportpatch_vary_headersfromdjango.utils.cryptoimportconstant_time_compare,get_random_stringfromdjango.utils.encodingimportforce_textfromdjango.utils.httpimportsame_originlogger=logging.getLogger('django.request')REASON_NO_REFERER="Referer checking failed - no Referer."REASON_BAD_REFERER="Referer checking failed - %s does not match %s."REASON_NO_CSRF_COOKIE="CSRF cookie not set."REASON_BAD_TOKEN="CSRF token missing or incorrect."CSRF_KEY_LENGTH=32def_get_failure_view():""" Returns the view to be used for CSRF rejections """returnget_callable(settings.CSRF_FAILURE_VIEW)def_get_new_csrf_key():returnget_random_string(CSRF_KEY_LENGTH)defget_token(request):""" Returns the CSRF token required for a POST form. The token is an alphanumeric value. A side effect of calling this function is to make the csrf_protect decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie' header to the outgoing response. For this reason, you may need to use this function lazily, as is done by the csrf context processor. """request.META["CSRF_COOKIE_USED"]=Truereturnrequest.META.get("CSRF_COOKIE",None)defrotate_token(request):""" Changes the CSRF token in use for a request - should be done on login for security purposes. """request.META.update({"CSRF_COOKIE_USED":True,"CSRF_COOKIE":_get_new_csrf_key(),})def_sanitize_token(token):# Allow only alphanumiflen(token)>CSRF_KEY_LENGTH:return_get_new_csrf_key()token=re.sub('[^a-zA-Z0-9]+','',force_text(token))iftoken=="":# In case the cookie has been truncated to nothing at some point.return_get_new_csrf_key()returntoken

[docs]classCsrfViewMiddleware(object):""" Middleware that requires a present and correct csrfmiddlewaretoken for POST requests that have a CSRF cookie, and sets an outgoing CSRF cookie. This middleware should be used in conjunction with the csrf_token template tag. """# The _accept and _reject methods currently only exist for the sake of the# requires_csrf_token decorator.def_accept(self,request):# Avoid checking the request twice by adding a custom attribute to# request. This will be relevant when both decorator and middleware# are used.request.csrf_processing_done=TruereturnNonedef_reject(self,request,reason):logger.warning('Forbidden (%s): %s',reason,request.path,extra={'status_code':403,'request':request,})return_get_failure_view()(request,reason=reason)defprocess_view(self,request,callback,callback_args,callback_kwargs):ifgetattr(request,'csrf_processing_done',False):returnNonetry:csrf_token=_sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME])# Use same token next timerequest.META['CSRF_COOKIE']=csrf_tokenexceptKeyError:csrf_token=None# Generate token and store it in the request, so it's# available to the view.request.META["CSRF_COOKIE"]=_get_new_csrf_key()# Wait until request.META["CSRF_COOKIE"] has been manipulated before# bailing out, so that get_token still worksifgetattr(callback,'csrf_exempt',False):returnNone# Assume that anything not defined as 'safe' by RFC2616 needs protectionifrequest.methodnotin('GET','HEAD','OPTIONS','TRACE'):ifgetattr(request,'_dont_enforce_csrf_checks',False):# Mechanism to turn off CSRF checks for test suite.# It comes after the creation of CSRF cookies, so that# everything else continues to work exactly the same# (e.g. cookies are sent, etc.), but before any# branches that call reject().returnself._accept(request)ifrequest.is_secure():# Suppose user visits http://example.com/# An active network attacker (man-in-the-middle, MITM) sends a# POST form that targets https://example.com/detonate-bomb/ and# submits it via JavaScript.## The attacker will need to provide a CSRF cookie and token, but# that's no problem for a MITM and the session-independent# nonce we're using. So the MITM can circumvent the CSRF# protection. This is true for any HTTP connection, but anyone# using HTTPS expects better! For this reason, for# https://example.com/ we need additional protection that treats# http://example.com/ as completely untrusted. Under HTTPS,# Barth et al. found that the Referer header is missing for# same-domain requests in only about 0.2% of cases or less, so# we can use strict Referer checking.referer=force_text(request.META.get('HTTP_REFERER'),strings_only=True,errors='replace')ifrefererisNone:returnself._reject(request,REASON_NO_REFERER)# Note that request.get_host() includes the port.good_referer='https://%s/'%request.get_host()ifnotsame_origin(referer,good_referer):reason=REASON_BAD_REFERER%(referer,good_referer)returnself._reject(request,reason)ifcsrf_tokenisNone:# No CSRF cookie. For POST requests, we insist on a CSRF cookie,# and in this way we can avoid all CSRF attacks, including login# CSRF.returnself._reject(request,REASON_NO_CSRF_COOKIE)# Check non-cookie token for match.request_csrf_token=""ifrequest.method=="POST":try:request_csrf_token=request.POST.get('csrfmiddlewaretoken','')exceptIOError:# Handle a broken connection before we've completed reading# the POST data. process_view shouldn't raise any# exceptions, so we'll ignore and serve the user a 403# (assuming they're still listening, which they probably# aren't because of the error).passifrequest_csrf_token=="":# Fall back to X-CSRFToken, to make things easier for AJAX,# and possible for PUT/DELETE.request_csrf_token=request.META.get('HTTP_X_CSRFTOKEN','')ifnotconstant_time_compare(request_csrf_token,csrf_token):returnself._reject(request,REASON_BAD_TOKEN)returnself._accept(request)defprocess_response(self,request,response):ifgetattr(response,'csrf_processing_done',False):returnresponse# If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was# never called, probably because a request middleware returned a response# (for example, contrib.auth redirecting to a login page).ifrequest.META.get("CSRF_COOKIE")isNone:returnresponseifnotrequest.META.get("CSRF_COOKIE_USED",False):returnresponse# Set the CSRF cookie even if it's already set, so we renew# the expiry timer.response.set_cookie(settings.CSRF_COOKIE_NAME,request.META["CSRF_COOKIE"],max_age=settings.CSRF_COOKIE_AGE,domain=settings.CSRF_COOKIE_DOMAIN,path=settings.CSRF_COOKIE_PATH,secure=settings.CSRF_COOKIE_SECURE,httponly=settings.CSRF_COOKIE_HTTPONLY)# Content varies with the CSRF cookie, so set the Vary header.patch_vary_headers(response,('Cookie',))response.csrf_processing_done=Truereturnresponse