def test_same_origin_true(self): # Identical self.assertTrue(http.same_origin('http://foo.com/', 'http://foo.com/')) # One with trailing slash - see #15617 self.assertTrue(http.same_origin('http://foo.com', 'http://foo.com/')) self.assertTrue(http.same_origin('http://foo.com/', 'http://foo.com')) # With port self.assertTrue(http.same_origin('https://foo.com:8000', 'https://foo.com:8000/'))
def test_same_origin_false(self): # Different scheme self.assertFalse(http.same_origin('http://foo.com', 'https://foo.com')) # Different host self.assertFalse(http.same_origin('http://foo.com', 'http://goo.com')) # Different host again self.assertFalse(http.same_origin('http://foo.com', 'http://foo.com.evil.com')) # Different port self.assertFalse(http.same_origin('http://foo.com:8000', 'http://foo.com:8001'))
def is_authenticated(self, request, **kwargs): """ """ # this is the line i have to override in order to get # POST request to successfully authenticate ## if request.method in ("GET", "POST", "DELETE"): return request.user.is_authenticated() if getattr(request, "_dont_enforce_csrf_checks", False): return request.user.is_authenticated() csrf_token = _sanitize_token(request.COOKIES.get(settings.CSRF_COOKIE_NAME, "")) if request.is_secure(): referer = request.META.get("HTTP_REFERER") if referer is None: return False good_referer = "https://%s/" % request.get_host() if not same_origin(referer, good_referer): return False request_csrf_token = request.META.get("HTTP_X_CSRFTOKEN", "") if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def get_audience(request): """ Determine the audience to use for verification from the given request. Relies on the BROWSERID_AUDIENCES setting, which is an explicit list of acceptable audiences for your site. :returns: The first audience in BROWSERID_AUDIENCES that has the same origin as the request's URL. :raises: :class:`django.core.exceptions.ImproperlyConfigured`: If BROWSERID_AUDIENCES isn't defined, or if no matching audience could be found. """ try: audiences = settings.BROWSERID_AUDIENCES except AttributeError: raise ImproperlyConfigured( 'Required setting BROWSERID_AUDIENCES not found!') protocol = 'https' if request.is_secure() else 'http' host = '{0}://{1}'.format(protocol, request.get_host()) for audience in audiences: if same_origin(host, audience): return audience # No audience found? We must not be configured properly, otherwise why are we getting this # request? raise ImproperlyConfigured( 'No audience could be found in BROWSERID_AUDIENCES for host `{0}`.'. format(host))
def process_view(self, request, callback, callback_args, callback_kwargs): """ Taken from django.middleware.csrf """ if request.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' ) if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port. good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) return self._reject(request, reason) return self._accept(request)
def try_sessions(self, request, **kwargs): """ Attempt to authenticate with sessions. Cribbed from a newer version of Tastypie than we're using. """ csrf_token = _sanitize_token(request.COOKIES.get(settings.CSRF_COOKIE_NAME, "")) if request.is_secure(): referer = request.META.get("HTTP_REFERER") if referer is None: return False good_referer = "https://%s/" % request.get_host() if not same_origin(referer, good_referer): return False # Tastypie docstring says accessing POST here isn't safe, but so far it's not causing any problems... # This is necessary for downloads that post the csrf token from an iframe request_csrf_token = request.META.get("HTTP_X_CSRFTOKEN", "") or request.POST.get("csrfmiddlewaretoken", "") if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def is_authenticated(self, request, **kwargs): """ Checks to make sure the user is logged in & has a Django session. """ # Cargo-culted from Django 1.3/1.4's ``django/middleware/csrf.py``. # We can't just use what's there, since the return values will be # wrong. # We also can't risk accessing ``request.POST``, which will break with # the serialized bodies. if request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): return request.user.is_authenticated() if getattr(request, '_dont_enforce_csrf_checks', False): return request.user.is_authenticated() csrf_token = _sanitize_token(request.COOKIES.get(settings.CSRF_COOKIE_NAME, '')) if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: return False good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return False request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def is_authenticated(self, request, **kwargs): """ """ # this is the line i have to override in order to get # POST request to successfully authenticate ## if request.method in ('GET', 'POST', 'DELETE'): return request.user.is_authenticated() if getattr(request, '_dont_enforce_csrf_checks', False): return request.user.is_authenticated() csrf_token = _sanitize_token(request.COOKIES.get(settings.CSRF_COOKIE_NAME, '')) if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: return False good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return False request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def get_audience(request): """ Determine the audience to use for verification from the given request. Relies on the BROWSERID_AUDIENCES setting, which is an explicit list of acceptable audiences for your site. :returns: The first audience in BROWSERID_AUDIENCES that has the same origin as the request's URL. :raises: :class:`django.core.exceptions.ImproperlyConfigured`: If BROWSERID_AUDIENCES isn't defined, or if no matching audience could be found. """ try: audiences = settings.BROWSERID_AUDIENCES except AttributeError: raise ImproperlyConfigured('Required setting BROWSERID_AUDIENCES not found!') protocol = 'https' if request.is_secure() else 'http' host = '{0}://{1}'.format(protocol, request.get_host()) for audience in audiences: if same_origin(host, audience): return audience # No audience found? We must not be configured properly, otherwise why are we getting this # request? raise ImproperlyConfigured('No audience could be found in BROWSERID_AUDIENCES for host `{0}`.' .format(host))
def is_authenticated(self, request, **kwargs): # this is the line i have to override in order to get # POST request to successfully authenticate ## if request.method in ['GET', 'POST', 'PATCH', 'DELETE']: return request.user.is_authenticated() if getattr(request, '_dont_enforce_csrf_checks', False): return request.user.is_authenticated() csrf_token = _sanitize_token( request.COOKIES.get(settings.CSRF_COOKIE_NAME, '')) if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: return False good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return False request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def try_sessions(self, request, **kwargs): """ Attempt to authenticate with sessions. Cribbed from a newer version of Tastypie than we're using. """ csrf_token = _sanitize_token( request.COOKIES.get(settings.CSRF_COOKIE_NAME, '')) if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: return False good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return False # Tastypie docstring says accessing POST here isn't safe, but so far it's not causing any problems... # This is necessary for downloads that post the csrf token from an iframe request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') or request.POST.get( 'csrfmiddlewaretoken', '') if not constant_time_compare(request_csrf_token, csrf_token): return False return request.user.is_authenticated()
def validate_ticket(self, ticket, service, renew=False, require_https=False): """ Given a ticket string and service identifier, validate the corresponding ``Ticket``. If validation succeeds, return the ``Ticket``. If validation fails, raise an appropriate error. If ``renew`` is ``True``, ``ServiceTicket`` validation will only succeed if the ticket was issued from the presentation of the user's primary credentials. If ``require_https`` is ``True``, ``ServiceTicket`` validation will only succeed if the service URL scheme is HTTPS. """ if not ticket: raise InvalidRequest("No ticket string provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicket("Ticket string %s is invalid" % ticket) try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise InvalidTicket("Ticket %s does not exist" % ticket) if t.is_consumed(): raise InvalidTicket("%s %s has already been used" % (t.name, ticket)) if t.is_expired(): raise InvalidTicket("%s %s has expired" % (t.name, ticket)) if not service: raise InvalidRequest("No service identifier provided") if require_https and not is_scheme_https(service): raise InvalidService("Service %s is not HTTPS" % service) if not is_valid_service_url(service): raise InvalidService("Service %s is not a valid %s URL" % (service, t.name)) try: if not same_origin(t.service, service): raise InvalidService("%s %s for service %s is invalid for " "service %s" % (t.name, ticket, t.service, service)) except AttributeError: pass try: if renew and not t.is_primary(): raise InvalidTicket("%s %s was not issued via primary " "credentials" % (t.name, ticket)) except AttributeError: pass logger.debug("Validated %s %s" % (t.name, ticket)) return t
def check_referer(request, skip_post=True): '''Check that the current referer match current origin. Post requests are usually ignored as they are already check by the CSRF middleware. ''' if skip_post and request.method == 'POST': return True referer = request.META.get('HTTP_REFERER') return referer and http.same_origin(request.build_absolute_uri(), referer)
def validate_ticket(self, ticket, service=None, renew=False): """ Given a ticket string, validate the corresponding ``Ticket`` returning the ``Ticket`` if valid. If validation fails, return ``False``. If ``service`` is provided and the ticket has a service attribute, the origin of the two services will be compared. Validation will only succeed if the service origins match. if ``renew`` is provided, the validation will only succeed if the ticket was issued from the presentation of the user's primary credentials. """ if not ticket: raise InvalidRequestError("No ticket string provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicketError("Ticket string %s is invalid" % ticket) title = self.model._meta.verbose_name.title() try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise InvalidTicketError("%s %s does not exist" % (title, ticket)) if t.is_consumed(): raise InvalidTicketError("%s %s has already been used" % (title, ticket)) t.consume() if t.is_expired(): raise InvalidTicketError("%s %s has expired" % (title, ticket)) if not service: raise InvalidRequestError("No service identifier provided") if not is_valid_service_url(service): raise InvalidServiceError("Service %s is not a valid %s URL" % (service, title)) if not same_origin(t.service, service): raise InvalidServiceError("%s %s for service %s is invalid for service %s" % (title, ticket, t.service, service)) if renew and not t.is_primary(): raise InvalidTicketError("%s %s was not issued via primary credentials" % (title, ticket)) logger.debug("Validated %s %s" % (title, ticket)) return t
def get_audience(request): try: audiences = settings.BROWSERID_AUDIENCES except AttributeError: raise ImproperlyConfigured('Required setting BROWSERID_AUDIENCES not found!') protocol = 'https' if request.is_secure() else 'http' host = '%s://%s' % (protocol, request.get_host()) for audience in audiences: if same_origin(host, audience): return audience raise ImproperlyConfigured('No audience could be found in BROWSERID_AUDIENCES for host `{0}`.' .format(host))
def get_audience(request): try: audiences = settings.BROWSERID_AUDIENCES except AttributeError: raise ImproperlyConfigured( 'Required setting BROWSERID_AUDIENCES not found!') protocol = 'https' if request.is_secure() else 'http' host = '%s://%s' % (protocol, request.get_host()) for audience in audiences: if same_origin(host, audience): return audience raise ImproperlyConfigured( 'No audience could be found in BROWSERID_AUDIENCES for host `{0}`.'. format(host))
def test_same_origin_true(self): # Identical self.assertTrue(http.same_origin('http://foo.com/', 'http://foo.com/')) # One with trailing slash - see #15617 self.assertTrue(http.same_origin('http://foo.com', 'http://foo.com/')) self.assertTrue(http.same_origin('http://foo.com/', 'http://foo.com')) # With port self.assertTrue(http.same_origin('https://foo.com:8000', 'https://foo.com:8000/')) # No port given but according to RFC6454 still the same origin self.assertTrue(http.same_origin('http://foo.com', 'http://foo.com:80/')) self.assertTrue(http.same_origin('https://foo.com', 'https://foo.com:443/'))
def _is_good_request(request): """ Temporarily sanitizing check. Look at https://github.com/django/django/blob/master/django/middleware/csrf.py TODO: remove this when we move the widget to django and let django's middleware handles this. @param request: http request @return: true or false """ is_good_request = True referer = request.META.get('HTTP_REFERER') if referer is None: is_good_request = False logger.warning(REASON_NO_REFERER) # Note that request.get_host() includes the port. good_referer = 'http://%s/' % request.get_host() if referer: if not same_origin(referer, good_referer): is_good_request = False logger.warning(REASON_BAD_REFERER.format(referer, good_referer)) return is_good_request
def manual_csrf_check(request): """ Performs a CSRF check for a specific request. Useful for in-view CSRF checks. Returns an HTTP response in case of CSRF failure. """ try: csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME] ) request.META['CSRF_COOKIE'] = csrf_token except KeyError: csrf_token = None request.META["CSRF_COOKIE"] = _get_new_csrf_key() if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: return middleware._reject(request, REASON_NO_REFERER) good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) return middleware._reject(request, reason) if csrf_token is None: return middleware._reject(request, REASON_NO_CSRF_COOKIE) request_csrf_token = "" if request.method == "POST": request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): return middleware._reject(request, REASON_BAD_TOKEN)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: cookie_token = request.COOKIES[settings.CSRF_COOKIE_NAME] except KeyError: csrf_token = None else: csrf_token = _sanitize_token(cookie_token) if csrf_token != cookie_token: # Cookie token needed to be replaced; # the cookie needs to be reset. request.csrf_cookie_needs_reset = True # Use same token next time. request.META['CSRF_COOKIE'] = csrf_token # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None # Assume that anything not defined as 'safe' by RFC7231 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(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(). return self._accept(request) if request.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 # secret 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 = base_referer = force_text( request.META.get('HTTP_REFERER'), strings_only=True, errors='replace' ) if referer is None: return self._reject(request, REASON_NO_REFERER) referer = urlparse(referer) # Make sure we have a valid URL for Referer. if '' in (referer.scheme, referer.netloc): return self._reject(request, REASON_MALFORMED_REFERER) # Ensure that our Referer is also secure. if referer.scheme != 'https': return self._reject(request, REASON_INSECURE_REFERER) # If there isn't a CSRF_COOKIE_DOMAIN, assume we need an exact # match on host:port. If not, obey the cookie rules. if settings.CSRF_COOKIE_DOMAIN is None: # request.get_host() includes the port. good_referer = request.get_host() else: good_referer = settings.CSRF_COOKIE_DOMAIN server_port = request.get_port() if server_port not in ('443', '80'): good_referer = '%s:%s' % (good_referer, server_port) # if not any(is_same_domain(referer.netloc, host) for host in good_hosts): # reason = REASON_BAD_REFERER % referer.geturl() good_referer = 'https://%s/' % request.get_host() if not same_origin(base_referer, good_referer): reason = REASON_BAD_REFERER % (base_referer, good_referer) return self._reject(request, reason) if csrf_token is None: # 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. return self._reject(request, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.method == "POST": try: request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') except IOError: # 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). pass if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX, # and possible for PUT/DELETE. 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)
def process_view(self, request, callback, callback_args, callback_kwargs): # 如果请求里面设置了csrf_done,则没有任何处理,一旦这个设置了,那么整个中间件都 # 不会产生作用 if getattr(request, 'csrf_processing_done', False): return None try: # 从cookie里面拿出之前设置的cookie,将其净化 csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token # 没有设置过,则在request中设置一个CSRF_COOKIE,这次请求必须是一个GET请求. # 如果开发的网站使用GET,HEAD等请求更新数据库(不符合规范),那么CSRF中间层不会 # 正确的验证,因此绝对不要这样. except KeyError: 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() # TODO:设置了就跳过这里的处理,下面的注释的意思 # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None # Assume that anything not defined as 'safe' by RFC2616 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): # 如果请求中设置了不要开启csrf检查则直接ok,应该是其他中间件可以控制的,如 # 果这个设置了,中间件只是处理response验证.以及设置个Cookie if getattr(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(). return self._accept(request) # 如果使用HTTPS,那么必须设置了refer并且和目标HOST一致. if request.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') if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port. good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) return self._reject(request, reason) # 没有csrf_token则拒绝,也就是说对网站的第一个请求必须是get,因为之后会设置csrf. if csrf_token is None: # 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. return self._reject(request, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. # 拿到其中的另一个csrf设置,对于POST,是csrfmt,对于其他,是HTTP_X_CSRFTOKEN # 判断这两个和POST中的是否一致. 可以POST.因为存在cookie中,而其他程序拿不到cookie值 # 能发送但是不能拿到,然后在加上另外的值其他程序就没办法了 request_csrf_token = "" if request.method == "POST": try: # 是Django模板系统设置的. request_csrf_token = request.POST.get( 'csrfmiddlewaretoken', '') except IOError: # 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). pass if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX, # and possible for PUT/DELETE. # TODO: 是哪里设置的?:视图,模板等设置的. request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, "csrf_processing_done", False): return None try: csrf_token = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META["CSRF_COOKIE"] = csrf_token except KeyError: print "Key Error and Reset the token now!Maybe you need set the cookie of client!" # ,request.COOKIES,request.META 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 works if getattr(callback, "csrf_exempt", False): return None # Assume that anything not defined as 'safe' by RFC2616 needs protection if request.method not in ("GET", "HEAD", "OPTIONS", "TRACE"): if getattr(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(). return self._accept(request) if request.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") if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port. good_referer = "https://%s/" % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) return self._reject(request, reason) """ !!!!!! When qiniu send the call back to server. the csrf can miss """ if "qiniu-callback" in request.META.get("HTTP_USER_AGENT", ""): return self._accept(request) if csrf_token is None: # 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. return self._reject(request, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.method == "POST": try: request_csrf_token = request.POST.get("csrfmiddlewaretoken", "") except IOError: # 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). pass if request_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", "") # print request.META """ When the Android send the token in the HTTP_COOKIE """ if request_csrf_token == "": request_csrf_token = request.META.get("HTTP_COOKIE", "") regToken = re.compile(r"csrftoken=(.*)") tokenResult = regToken.findall(request_csrf_token) print 1, tokenResult if len(tokenResult) != 1: request_csrf_token = "" else: request_csrf_token = tokenResult[0] # When Ajax send the cookie csrftoken=JZ4U3CGWouhRu8TYDVBCXqggqVc9LAgY; request-use-base64=false # find the ';' and record the token before it. iSubTemp = request_csrf_token.find(";") if iSubTemp > 0: request_csrf_token = request_csrf_token[:iSubTemp] """ Get the token from Json's data """ if request_csrf_token == "" and "application/json" in request.META.get("CONTENT_TYPE", ""): # When the Token sent by client in the JSON body jsondata = simplejson.loads(request.body) if isinstance(jsondata, dict): request_csrf_token = simplejson.loads(request.body).get("csrfmiddlewaretoken", "") elif isinstance(jsondata, list): request_csrf_token = simplejson.loads(request.body)[0].get("csrfmiddlewaretoken", "") else: pass print 10, request_csrf_token, 11, csrf_token if not constant_time_compare(request_csrf_token, csrf_token): return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = django_csrf._sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token except KeyError: csrf_token = None # Generate token and store it in the request, so it's # available to the view. request.META["CSRF_COOKIE"] = django_csrf._get_new_csrf_key() # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None # Assume that anything not defined as 'safe' by RFC2616 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(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(). return self._accept(request) if request.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') if referer is None: return self._reject(request, django_csrf.REASON_NO_REFERER) # Here we generate a list of all acceptable HTTP referers, # including the current host since that has been validated # upstream. good_hosts = list(settings.CSRF_TRUSTED_ORIGINS) # Note that request.get_host() includes the port. good_hosts.append(request.get_host()) good_referers = [ 'https://{0}/'.format(host) for host in good_hosts ] if not any( same_origin(referer, host) for host in good_referers): reason = REASON_BAD_REFERER % referer return self._reject(request, reason) if csrf_token is None: # 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. return self._reject(request, django_csrf.REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.method == "POST": try: request_csrf_token = request.POST.get( 'csrfmiddlewaretoken', '') except IOError: # 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). pass if request_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', '') if not constant_time_compare(request_csrf_token, csrf_token): return self._reject(request, django_csrf.REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token except KeyError: csrf_token = None # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None # Assume that anything not defined as 'safe' by RFC2616 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(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(). return self._accept(request) if request.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' ) if referer is None: return self._reject(request, REASON_NO_REFERER) # Here we generate a list of all acceptable HTTP referers, # including the current host since that has been validated # upstream. good_hosts = list(settings.CSRF_TRUSTED_ORIGINS) # Note that request.get_host() includes the port. good_hosts.append(request.get_host()) good_referers = ['https://{0}/'.format(host) for host in good_hosts] if not any(same_origin(referer, host) for host in good_referers): reason = REASON_BAD_REFERER % referer return self._reject(request, reason) if csrf_token is None: # 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. return self._reject(request, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.method == "POST": try: request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') except IOError: # 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). pass if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX, # and possible for PUT/DELETE. request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '') if not constant_time_compare(request_csrf_token, csrf_token): return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. try: # In case of cookies from untrusted sources, we strip anything # dangerous at this point, so that the cookie + token will have the # same, sanitized value. request.META["CSRF_COOKIE"] = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: # No cookie, so create one. This will be sent with the next # response. request.META["CSRF_COOKIE"] = _get_new_csrf_key() # Set a flag to allow us to fall back and allow the session id in # place of a CSRF cookie for this request only. cookie_is_new = True # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Strict referer checking for HTTPS referer = request.META.get('HTTP_REFERER') if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return self._reject(request, REASON_BAD_REFERER % (referer, good_referer)) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not # rejected if the form was sent to the user before upgrading to the # Django 1.2 method (session independent nonce) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: # No CSRF cookie and no session cookie. For POST requests, # we insist on a CSRF cookie, and in this way we can avoid # all CSRF attacks, including login CSRF. return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', "") if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if request_csrf_token != csrf_token: if cookie_is_new: # probably a problem setting the CSRF cookie return self._reject(request, REASON_NO_CSRF_COOKIE) else: return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def handle(self, request, data): if 'user_name' in request.session: if request.session['user_name'] != data['username']: # To avoid reusing another user's session, create a # new, empty session if the existing session # corresponds to a different authenticated user. request.session.flush() # Always cycle the session key when viewing the login form to # prevent session fixation request.session.cycle_key() # For now we'll allow fallback to OPENSTACK_KEYSTONE_URL if the # form post doesn't include a region. # jt default_region = (settings.OPENSTACK_KEYSTONE_URL, "Default Region") regions = getattr(settings, 'AVAILABLE_REGIONS', [default_region]) #endpoint = data.get('region', None) or settings.OPENSTACK_KEYSTONE_URL #region_name = dict(self.fields['region'].choices)[endpoint] region_name = data.get('region', None) or "Default Region" endpoint = [r[0] for r in regions if r[1] == region_name][0] request.session['region_endpoint'] = endpoint request.session['region_name'] = region_name redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, None) # Make sure the requested redirect matches the protocol, # domain, and port of this request if redirect_to and not same_origin( request.build_absolute_uri(redirect_to), request.build_absolute_uri()): redirect_to = None if data.get('tenant', None): try: token = api.token_create(request, data.get('tenant'), data['username'], data['password']) tenants = api.tenant_list_for_token(request, token.id) except: msg = _('Unable to authenticate for that project.') exceptions.handle(request, message=msg, escalate=True) _set_session_data(request, token) user = users.get_user_from_request(request) redirect = redirect_to or base.Horizon.get_user_home(user) return shortcuts.redirect(redirect) elif data.get('username', None): try: unscoped_token = api.token_create(request, '', data['username'], data['password']) except keystone_exceptions.Unauthorized: exceptions.handle(request, _('Invalid user name or password.')) except: # If we get here we don't want to show a stack trace to the # user. However, if we fail here, there may be bad session # data that's been cached already. request.user_logout() exceptions.handle(request, message=_("An error occurred authenticating." " Please try again later."), escalate=True) # Unscoped token request.session['unscoped_token'] = unscoped_token.id request.user.username = data['username'] # Get the tenant list, and log in using first tenant # FIXME (anthony): add tenant chooser here? try: tenants = api.tenant_list_for_token(request, unscoped_token.id) except: exceptions.handle(request) tenants = [] # Abort if there are no valid tenants for this user if not tenants: messages.error(request, _('You are not authorized for any projects.') % {"user": data['username']}, extra_tags="login") return # Create a token. # NOTE(gabriel): Keystone can return tenants that you're # authorized to administer but not to log into as a user, so in # the case of an Unauthorized error we should iterate through # the tenants until one succeeds or we've failed them all. while tenants: tenant = tenants.pop() try: token = api.token_create_scoped(request, tenant.id, unscoped_token.id) break except: # This will continue for recognized Unauthorized # exceptions from keystoneclient. exceptions.handle(request, ignore=True) token = None if token is None: raise exceptions.NotAuthorized( _("You are not authorized for any available projects.")) _set_session_data(request, token) user = users.get_user_from_request(request) redirect = redirect_to or base.Horizon.get_user_home(user) return shortcuts.redirect(redirect)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. try: # In case of cookies from untrusted sources, we strip anything # dangerous at this point, so that the cookie + token will have the # same, sanitized value. request.META["CSRF_COOKIE"] = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: # No cookie, so create one. This will be sent with the next # response. request.META["CSRF_COOKIE"] = _get_new_csrf_key() # Set a flag to allow us to fall back and allow the session id in # place of a CSRF cookie for this request only. cookie_is_new = True # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Strict referer checking for HTTPS referer = request.META.get('HTTP_REFERER') if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): return self._reject( request, REASON_BAD_REFERER % (referer, good_referer)) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not # rejected if the form was sent to the user before upgrading to the # Django 1.2 method (session independent nonce) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: # No CSRF cookie and no session cookie. For POST requests, # we insist on a CSRF cookie, and in this way we can avoid # all CSRF attacks, including login CSRF. return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', "") if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if request_csrf_token != csrf_token: if cookie_is_new: # probably a problem setting the CSRF cookie return self._reject(request, REASON_NO_CSRF_COOKIE) else: return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: request.META["CSRF_COOKIE"] = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: request.META["CSRF_COOKIE"] = _get_new_csrf_key() cookie_is_new = True if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(request, '_dont_enforce_csrf_checks', False): return self._accept(request) # let initial signed requests pass if 'signed_request' in request.POST: post = request.POST.copy() post.pop('signed_request') if len(post) == 0: return self._accept(request) if request.is_secure() and getattr(settings, 'HTTPS_REFERER_REQUIRED', True): referer = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, reason) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: logger.warning('Forbidden (%s): %s' % (REASON_NO_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', None) if not request_csrf_token: request_csrf_token = request.POST.get('state', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): if cookie_is_new: # probably a problem setting the CSRF cookie logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. try: # In case of cookies from untrusted sources, we strip anything # dangerous at this point, so that the cookie + token will have the # same, sanitized value. request.META["CSRF_COOKIE"] = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: # No cookie, so create one. This will be sent with the next # response. request.META["CSRF_COOKIE"] = _get_new_csrf_key() # Set a flag to allow us to fall back and allow the session id in # place of a CSRF cookie for this request only. cookie_is_new = True # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ # An active network attacker,(man-in-the-middle, MITM) sends a # POST form which targets https://example.com/detonate-bomb/ and # submits it via javascript. # # The attacker will need to provide a CSRF cookie and token, but # that is no problem for a MITM and the session independent # nonce we are 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 = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, reason) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not # rejected if the form was sent to the user before upgrading to the # Django 1.2 method (session independent nonce) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: # No CSRF cookie and no session cookie. For POST requests, # we insist on a CSRF cookie, and in this way we can avoid # all CSRF attacks, including login CSRF. logger.warning('Forbidden (%s): %s' % (REASON_NO_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): if cookie_is_new: # probably a problem setting the CSRF cookie logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. try: # In case of cookies from untrusted sources, we strip anything # dangerous at this point, so that the cookie + token will have the # same, sanitized value. request.META["CSRF_COOKIE"] = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: # No cookie, so create one. This will be sent with the next # response. request.META["CSRF_COOKIE"] = _get_new_csrf_key() # Set a flag to allow us to fall back and allow the session id in # place of a CSRF cookie for this request only. cookie_is_new = True # Wait until request.META["CSRF_COOKIE"] has been manipulated before # bailing out, so that get_token still works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ # An active network attacker,(man-in-the-middle, MITM) sends a # POST form which targets https://example.com/detonate-bomb/ and # submits it via javascript. # # The attacker will need to provide a CSRF cookie and token, but # that is no problem for a MITM and the session independent # nonce we are 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 = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, reason) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not # rejected if the form was sent to the user before upgrading to the # Django 1.2 method (session independent nonce) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: # No CSRF cookie and no session cookie. For POST requests, # we insist on a CSRF cookie, and in this way we can avoid # all CSRF attacks, including login CSRF. logger.warning('Forbidden (%s): %s' % (REASON_NO_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): if cookie_is_new: # probably a problem setting the CSRF cookie logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token except KeyError: 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 works if getattr(callback, 'csrf_exempt', False): return None # Assume that anything not defined as 'safe' by RFC2616 needs protection if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(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(). return self._accept(request) if request.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 = request.META.get('HTTP_REFERER') if referer is None: return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port. good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) return self._reject(request, reason) if csrf_token is None: # 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. return self._reject(request, REASON_NO_CSRF_COOKIE) # Check non-cookie token for match. request_csrf_token = "" if request.method == "POST": request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_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', '') if not constant_time_compare(request_csrf_token, csrf_token): return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token except KeyError: 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 works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ # An active network attacker,(man-in-the-middle, MITM) sends a # POST form which targets https://example.com/detonate-bomb/ and # submits it via javascript. # # The attacker will need to provide a CSRF cookie and token, but # that is no problem for a MITM and the session independent # nonce we are 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 = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, reason) if csrf_token is None: # 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. logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_NO_CSRF_COOKIE) # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, }) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = _sanitize_token( request.COOKIES[settings.CSRF_COOKIE_NAME]) request.META['CSRF_COOKIE'] = csrf_token except KeyError: csrf_token = None request.META["CSRF_COOKIE"] = get_random_string(CSRF_KEY_LENGTH) if getattr(callback, 'csrf_exempt', False): return None if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): if getattr(request, '_dont_enforce_csrf_checks', False): return self._accept(request) if request.is_secure(): referer = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s', REASON_NO_REFERER, request.path, extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_REFERER) good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s', reason, request.path, extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, reason) if csrf_token is None: logger.warning('Forbidden (%s): %s', REASON_NO_CSRF_COOKIE, request.path, extra={ 'status_code': 403, 'request': request, } ) _send_email_about_cookies(request, REASON_NO_CSRF_COOKIE) return self._reject(request, REASON_NO_CSRF_COOKIE) request_csrf_token = "" if request.method == "POST": request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): logger.warning('Forbidden (%s): %s', REASON_BAD_TOKEN, request.path, extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: request.META["CSRF_COOKIE"] = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) cookie_is_new = False except KeyError: request.META["CSRF_COOKIE"] = _get_new_csrf_key() cookie_is_new = True if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(request, '_dont_enforce_csrf_checks', False): return self._accept(request) if request.is_secure() and getattr(settings, 'HTTPS_REFERER_REQUIRED', True): referer = request.META.get('HTTP_REFERER') if referer is None : logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, reason) if cookie_is_new: try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] csrf_token = _make_legacy_session_token(session_id) except KeyError: logger.warning('Forbidden (%s): %s' % (REASON_NO_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', None) if not request_csrf_token: request_csrf_token = request.POST.get('state', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): if cookie_is_new: # probably a problem setting the CSRF cookie logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)
def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None try: csrf_token = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) # Use same token next time request.META['CSRF_COOKIE'] = csrf_token except KeyError: 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 works if getattr(callback, 'csrf_exempt', False): return None if request.method == 'POST': if getattr(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 the # any branches that call reject() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ # An active network attacker,(man-in-the-middle, MITM) sends a # POST form which targets https://example.com/detonate-bomb/ and # submits it via javascript. # # The attacker will need to provide a CSRF cookie and token, but # that is no problem for a MITM and the session independent # nonce we are 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 = request.META.get('HTTP_REFERER') if referer is None: logger.warning('Forbidden (%s): %s' % (REASON_NO_REFERER, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_REFERER) # Note that request.get_host() includes the port good_referer = 'https://%s/' % request.get_host() if not same_origin(referer, good_referer): reason = REASON_BAD_REFERER % (referer, good_referer) logger.warning('Forbidden (%s): %s' % (reason, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, reason) if csrf_token is None: # 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. logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_NO_CSRF_COOKIE) # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') if request_csrf_token == "": # Fall back to X-CSRFToken, to make things easier for AJAX request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ 'status_code': 403, 'request': request, } ) return self._reject(request, REASON_BAD_TOKEN) return self._accept(request)