crosscompute / jupyterlab-crosscompute

CrossCompute Extensions for JupyterLab: Automate Reports Using Python + Markdown + CSS
BSD 3-Clause "New" or "Revised" License
2 stars 1 forks source link

Insecure Mixed Content #37

Open invisibleroads opened 8 months ago

invisibleroads commented 8 months ago

@AbdourahamaneIssakaSani is accessing jupyterlab via HTTPS, but this fetch method is querying by HTTP, resulting in an insecure mixed content request block.

He seems to be running the latest versions of chrome and firefox. Could it be possible that a proxy is causing this issue? We have not encountered this issue before and the change from HTTPS to HTTP does not happen if I access the same URL from my machine.

        fetch(uri, { method: 'HEAD' }).then(() => {
          launch.isReady = true;
          model.changed.emit();
          clearInterval(launchIntervalId);
        });

https://github.com/crosscompute/jupyterlab-crosscompute/blob/master/src/body.tsx#L273

origin_uri = headers['Origin']

https://github.com/crosscompute/jupyterlab-crosscompute/blob/master/jupyterlab_crosscompute/routines.py#L61

Looking at the code, we are relying on the Origin request header being correct. It is possible that @AbdourahamaneIssakaSani's machine is incorrectly reporting the Origin request header.

invisibleroads commented 8 months ago

Reading https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin, there are situations when a browser will not send the ORIGIN header:

Broadly speaking, user agents add the [Origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin) request header to:

    [cross origin](https://developer.mozilla.org/en-US/docs/Glossary/CORS) requests.
    [same-origin](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) requests except for [GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) or [HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) requests (i.e. they are added to same-origin [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST), [OPTIONS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS), [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT), [PATCH](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH), and [DELETE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE) requests).

There are some exceptions to the above rules; for example, if a cross-origin [GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) or [HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) request is made in [no-cors mode](https://developer.mozilla.org/en-US/docs/Web/API/Request/mode#value), the Origin header will not be added.
    requestAPI<any>('launch?folder=' + folder)
      .then(d => {
        delete this._model.error;
        this._model.launch = d;
        this._model.changed.emit();
      })

https://github.com/crosscompute/jupyterlab-crosscompute/blob/master/src/body.tsx#L41

As seen above, the launch state (including the URI) is set after a GET request to launch. If this GET request does not properly send the right Origin header, then the uri will be set incorrectly and the subsequent HEAD request will fail, resulting in the "Development Server" link failing to appear.

I think the environment variable method will be more reliable and we should only use the Origin request header as a fallback.

invisibleroads commented 8 months ago

The GET request to /launch is triggered when the file browser changes path.

    const refresh = () =>
      automationBody.updateModel({ folder: '/' + browserModel.path });
    browserModel.pathChanged.connect(refresh);
    labShell.layoutModified.connect(refresh);

https://github.com/crosscompute/jupyterlab-crosscompute/blob/master/src/index.ts#L41

From talking with @AbdourahamaneIssakaSani, it seems that his browser is sending Referer but not Origin for some reason. Either way, we shouldn't rely on the request headers.

{
    "Request Headers (1.272 kB)": {
        "headers": [
            {
                "name": "Accept",
                "value": "*/*"
            },
            {
                "name": "Accept-Encoding",
                "value": "gzip, deflate, br"
            },
            {
                "name": "Accept-Language",
                "value": "en-US,en;q=0.5"
            },
            {
                "name": "Cache-Control",
                "value": "no-cache"
            },
            {
                "name": "Connection",
                "value": "keep-alive"
            },
            {
                "name": "Content-Type",
                "value": "application/json"
            },
            {
                "name": "Host",
                "value": "crosscompute.net"
            },
            {
                "name": "Pragma",
                "value": "no-cache"
            },
            {
                "name": "Referer",
                "value": "https://crosscompute.net/ports/a/learn-examples-in-jupyterlab/b/REDACTED/l/jupyterlab/lab"
            },
            {
                "name": "Sec-Fetch-Dest",
                "value": "empty"
            },
            {
                "name": "Sec-Fetch-Mode",
                "value": "cors"
            },
            {
                "name": "Sec-Fetch-Site",
                "value": "same-origin"
            },
            {
                "name": "TE",
                "value": "trailers"
            },
            {
                "name": "User-Agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0"
            }
        ]
    }
}