@@ -285,8 +285,12 @@ def check_origin(self, origin_to_satisfy_tornado=""):
285
285
host = self .request .headers .get ("Host" )
286
286
origin = self .request .headers .get ("Origin" )
287
287
288
- # If no header is provided, assume it comes from a script/curl.
289
- # We are only concerned with cross-site browser stuff here.
288
+ # If no header is provided, allow it.
289
+ # Origin can be None for:
290
+ # - same-origin (IE, Firefox)
291
+ # - Cross-site POST form (IE, Firefox)
292
+ # - Scripts
293
+ # The cross-site POST (XSRF) case is handled by tornado's xsrf_token
290
294
if origin is None or host is None :
291
295
return True
292
296
@@ -338,6 +342,7 @@ def template_namespace(self):
338
342
contents_js_source = self .contents_js_source ,
339
343
version_hash = self .version_hash ,
340
344
ignore_minified_js = self .ignore_minified_js ,
345
+ xsrf_form_html = self .xsrf_form_html ,
341
346
** self .jinja_template_vars
342
347
)
343
348
@@ -401,6 +406,15 @@ def prepare(self):
401
406
raise web .HTTPError (404 )
402
407
return super (APIHandler , self ).prepare ()
403
408
409
+ def check_xsrf_cookie (self ):
410
+ """Check non-empty body on POST for XSRF
411
+
412
+ instead of checking the cookie for forms.
413
+ """
414
+ if self .request .method .upper () == 'POST' and not self .request .body :
415
+ # Require non-empty POST body for XSRF
416
+ raise web .HTTPError (400 , "POST requests must have a JSON body. If no content is needed, use '{}'." )
417
+
404
418
@property
405
419
def content_security_policy (self ):
406
420
csp = '; ' .join ([
0 commit comments