diff --git a/tornado/web.py b/tornado/web.py index ee9cbd32d4..71603342da 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -709,16 +709,27 @@ def xsrf_token(self): def check_xsrf_cookie(self): """Verifies that the '_xsrf' cookie matches the '_xsrf' argument. - To prevent cross-site request forgery, we set an '_xsrf' cookie - and include the same '_xsrf' value as an argument with all POST - requests. If the two do not match, we reject the form submission - as a potential forgery. + To prevent cross-site request forgery, we set an '_xsrf' + cookie and include the same value as a non-cookie + field with all POST requests. If the two do not match, we + reject the form submission as a potential forgery. + + The _xsrf value may be set as either a form field named _xsrf + or in a custom HTTP header named X-XSRFToken or X-CSRFToken + (the latter is accepted for compatibility with Django). See http://en.wikipedia.org/wiki/Cross-site_request_forgery + + Prior to release 1.1.1, this check was ignored if the HTTP header + "X-Requested-With: XMLHTTPRequest" was present. This exception + has been shown to be insecure and has been removed. For more + information please see + http://www.djangoproject.com/weblog/2011/feb/08/security/ + http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails """ - if self.request.headers.get("X-Requested-With") == "XMLHttpRequest": - return - token = self.get_argument("_xsrf", None) + token = (self.get_argument("_xsrf", None) or + self.request.headers.get("X-Xsrftoken") or + self.request.headers.get("X-Csrftoken")) if not token: raise HTTPError(403, "'_xsrf' argument missing from POST") if self.xsrf_token != token: