Skip to content

Commit

Permalink
Block cross-origin GET,HEAD requests with mismatched Referer
Browse files Browse the repository at this point in the history
- /files/ downloads must come from a local page (no direct visits or external links)
- same for /api/ requests
- disabling xsrf checks
  • Loading branch information
minrk committed Mar 8, 2019
1 parent d7becaf commit 7f7bfee
Showing 1 changed file with 57 additions and 1 deletion.
58 changes: 57 additions & 1 deletion notebook/base/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,13 +400,69 @@ def check_origin(self, origin_to_satisfy_tornado=""):
)
return allow

def check_referer(self):
"""Check Referer for cross-site requests.
Disables requests to certain endpoints with
external or missing Referer.
If set, allow_origin settings are applied to the Referer
to whitelist specific cross-origin sites.
Used on GET for api endpoints and /files/
to block cross-site inclusion (XSSI).
"""
host = self.request.headers.get("Host")
referer = self.request.headers.get("Referer")

if not host:
self.log.warning("Blocking request with no host")
return False
if not referer:
self.log.warning("Blocking request with no referer")
return False

referer_url = urlparse(referer)
referer_host = referer_url.netloc
if referer_host == host:
return True

# apply cross-origin checks to Referer:
origin = "{}://{}".format(referer_url.scheme, referer_url.netloc)
if self.allow_origin:
allow = self.allow_origin == origin
elif self.allow_origin_pat:
allow = bool(self.allow_origin_pat.match(origin))
else:
# No CORS settings, deny the request
allow = False

if not allow:
self.log.warning("Blocking Cross Origin request for %s. Referer: %s, Host: %s",
self.request.path, origin, host,
)
return allow

def check_xsrf_cookie(self):
"""Bypass xsrf cookie checks when token-authenticated"""
if self.token_authenticated or self.settings.get('disable_check_xsrf', False):
# Token-authenticated requests do not need additional XSRF-check
# Servers without authentication are vulnerable to XSRF
return
return super(IPythonHandler, self).check_xsrf_cookie()
try:
return super(IPythonHandler, self).check_xsrf_cookie()
except web.HTTPError as e:
if self.request.method in {'GET', 'HEAD'}:
# Consider Referer a sufficient cross-origin check for GET requests
if not self.check_referer():
referer = self.request.headers.get('Referer')
if referer:
msg = "Blocking Cross Origin request from {}.".format(referer)
else:
msg = "Blocking request from unknown origin"
raise web.HTTPError(403, msg)
else:
raise

def check_host(self):
"""Check the host header if remote access disallowed.
Expand Down

3 comments on commit 7f7bfee

@DS-AI
Copy link

@DS-AI DS-AI commented on 7f7bfee Apr 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit breaks IE file downloads since it sends no referrer!!! Test please!

@sangramga
Copy link

@sangramga sangramga commented on 7f7bfee May 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@minrk This commit breaks the Download Files (On Chrome and Firefox) - when running jupyter notebook behind a reverse proxy. Behind reverse proxy I have CORS settings as NotebookApp.allow_origin = "*",
Since in this scenario the origin of GET /files/ request (Download) will not be the same as host (on which jupyter notebook is running). Origin: https://test.example.com and host: 10.0.0.108:8000 .

Also NotebookApp.allow_origin = "*" also has no effect on check_referer() method, since it checks **self.allow_origin == origin**

Is it possible to add another check in check_referer() method for the above use case - as there is a same kind of check in check_origin() method - the following check.

if self.allow_origin == '*' or self.skip_check_origin():
    return True

The issue is officially reported at #4541

@meeseeksmachine
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on Jupyter Community Forum. There might be relevant details there:

https://discourse.jupyter.org/t/feature-idea-jupyter-books-as-a-landing-page-for-hub-log-ins/7831/13

Please sign in to comment.