mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-30 12:11:32 +08:00
19d23e2de7
* Issue #2502: Add line break after The Jupyter Notebook is running at:
* Revert "Issue #2502: Add line break after The Jupyter Notebook is running at:"
This reverts commit 3aa65e7120
.
* Issue #2502: Reverted previous changes and redone without strip trailing spaces
228 lines
8.7 KiB
ReStructuredText
228 lines
8.7 KiB
ReStructuredText
|
|
.. _server_security:
|
|
|
|
Security in the Jupyter notebook server
|
|
=======================================
|
|
|
|
Since access to the Jupyter notebook server means access to running arbitrary code,
|
|
it is important to restrict access to the notebook server.
|
|
For this reason, notebook 4.3 introduces token-based authentication that is **on by default**.
|
|
|
|
.. note::
|
|
|
|
If you enable a password for your notebook server,
|
|
token authentication is not enabled by default,
|
|
and the behavior of the notebook server is unchanged from versions earlier than 4.3.
|
|
|
|
When token authentication is enabled, the notebook uses a token to authenticate requests.
|
|
This token can be provided to login to the notebook server in three ways:
|
|
|
|
- in the ``Authorization`` header, e.g.::
|
|
|
|
Authorization: token abcdef...
|
|
|
|
- In a URL parameter, e.g.::
|
|
|
|
https://my-notebook/tree/?token=abcdef...
|
|
|
|
- In the password field of the login form that will be shown to you if you are not logged in.
|
|
|
|
When you start a notebook server with token authentication enabled (default),
|
|
a token is generated to use for authentication.
|
|
This token is logged to the terminal, so that you can copy/paste the URL into your browser::
|
|
|
|
[I 11:59:16.597 NotebookApp] The Jupyter Notebook is running at:
|
|
http://localhost:8888/?token=c8de56fa4deed24899803e93c227592aef6538f93025fe01
|
|
|
|
|
|
If the notebook server is going to open your browser automatically
|
|
(the default, unless ``--no-browser`` has been passed),
|
|
an *additional* token is generated for launching the browser.
|
|
This additional token can be used only once,
|
|
and is used to set a cookie for your browser once it connects.
|
|
After your browser has made its first request with this one-time-token,
|
|
the token is discarded and a cookie is set in your browser.
|
|
|
|
At any later time, you can see the tokens and URLs for all of your running servers with :command:`jupyter notebook list`::
|
|
|
|
$ jupyter notebook list
|
|
Currently running servers:
|
|
http://localhost:8888/?token=abc... :: /home/you/notebooks
|
|
https://0.0.0.0:9999/?token=123... :: /tmp/public
|
|
http://localhost:8889/ :: /tmp/has-password
|
|
|
|
For servers with token-authentication enabled, the URL in the above listing will include the token,
|
|
so you can copy and paste that URL into your browser to login.
|
|
If a server has no token (e.g. it has a password or has authentication disabled),
|
|
the URL will not include the token argument.
|
|
Once you have visited this URL,
|
|
a cookie will be set in your browser and you won't need to use the token again,
|
|
unless you switch browsers, clear your cookies, or start a notebook server on a new port.
|
|
|
|
Alternatives to token authentication
|
|
------------------------------------
|
|
|
|
If a generated token doesn't work well for you,
|
|
you can set a password for your notebook.
|
|
:command:`jupyter notebook password` will prompt you for a password,
|
|
and store the hashed password in your :file:`jupyter_notebook_config.json`.
|
|
|
|
.. versionadded:: 5.0
|
|
|
|
:command:`jupyter notebook password` command is added.
|
|
|
|
|
|
It is possible disable authentication altogether by setting the token and password to empty strings,
|
|
but this is **NOT RECOMMENDED**, unless authentication or access restrictions are handled at a different layer in your web application:
|
|
|
|
.. sourcecode:: python
|
|
|
|
c.NotebookApp.token = ''
|
|
c.NotebookApp.password = ''
|
|
|
|
|
|
.. _notebook_security:
|
|
|
|
Security in notebook documents
|
|
==============================
|
|
|
|
As Jupyter notebooks become more popular for sharing and collaboration,
|
|
the potential for malicious people to attempt to exploit the notebook
|
|
for their nefarious purposes increases. IPython 2.0 introduced a
|
|
security model to prevent execution of untrusted code without explicit
|
|
user input.
|
|
|
|
The problem
|
|
-----------
|
|
|
|
The whole point of Jupyter is arbitrary code execution. We have no
|
|
desire to limit what can be done with a notebook, which would negatively
|
|
impact its utility.
|
|
|
|
Unlike other programs, a Jupyter notebook document includes output.
|
|
Unlike other documents, that output exists in a context that can execute
|
|
code (via Javascript).
|
|
|
|
The security problem we need to solve is that no code should execute
|
|
just because a user has **opened** a notebook that **they did not
|
|
write**. Like any other program, once a user decides to execute code in
|
|
a notebook, it is considered trusted, and should be allowed to do
|
|
anything.
|
|
|
|
Our security model
|
|
------------------
|
|
|
|
- Untrusted HTML is always sanitized
|
|
- Untrusted Javascript is never executed
|
|
- HTML and Javascript in Markdown cells are never trusted
|
|
- **Outputs** generated by the user are trusted
|
|
- Any other HTML or Javascript (in Markdown cells, output generated by
|
|
others) is never trusted
|
|
- The central question of trust is "Did the current user do this?"
|
|
|
|
The details of trust
|
|
--------------------
|
|
|
|
When a notebook is executed and saved, a signature is computed from a
|
|
digest of the notebook's contents plus a secret key. This is stored in a
|
|
database, writable only by the current user. By default, this is located at::
|
|
|
|
~/.local/share/jupyter/nbsignatures.db # Linux
|
|
~/Library/Jupyter/nbsignatures.db # OS X
|
|
%APPDATA%/jupyter/nbsignatures.db # Windows
|
|
|
|
Each signature represents a series of outputs which were produced by code the
|
|
current user executed, and are therefore trusted.
|
|
|
|
When you open a notebook, the server computes its signature, and checks if it's
|
|
in the database. If a match is found, HTML and Javascript
|
|
output in the notebook will be trusted at load, otherwise it will be
|
|
untrusted.
|
|
|
|
Any output generated during an interactive session is trusted.
|
|
|
|
Updating trust
|
|
**************
|
|
|
|
A notebook's trust is updated when the notebook is saved. If there are
|
|
any untrusted outputs still in the notebook, the notebook will not be
|
|
trusted, and no signature will be stored. If all untrusted outputs have
|
|
been removed (either via ``Clear Output`` or re-execution), then the
|
|
notebook will become trusted.
|
|
|
|
While trust is updated per output, this is only for the duration of a
|
|
single session. A newly loaded notebook file is either trusted or not in its
|
|
entirety.
|
|
|
|
Explicit trust
|
|
**************
|
|
|
|
Sometimes re-executing a notebook to generate trusted output is not an
|
|
option, either because dependencies are unavailable, or it would take a
|
|
long time. Users can explicitly trust a notebook in two ways:
|
|
|
|
- At the command-line, with::
|
|
|
|
jupyter trust /path/to/notebook.ipynb
|
|
|
|
- After loading the untrusted notebook, with ``File / Trust Notebook``
|
|
|
|
These two methods simply load the notebook, compute a new signature, and add
|
|
that signature to the user's database.
|
|
|
|
Reporting security issues
|
|
-------------------------
|
|
|
|
If you find a security vulnerability in Jupyter, either a failure of the
|
|
code to properly implement the model described here, or a failure of the
|
|
model itself, please report it to security@ipython.org.
|
|
|
|
If you prefer to encrypt your security reports,
|
|
you can use :download:`this PGP public key <ipython_security.asc>`.
|
|
|
|
Affected use cases
|
|
------------------
|
|
|
|
Some use cases that work in Jupyter 1.0 became less convenient in
|
|
2.0 as a result of the security changes. We do our best to minimize
|
|
these annoyances, but security is always at odds with convenience.
|
|
|
|
Javascript and CSS in Markdown cells
|
|
************************************
|
|
|
|
While never officially supported, it had become common practice to put
|
|
hidden Javascript or CSS styling in Markdown cells, so that they would
|
|
not be visible on the page. Since Markdown cells are now sanitized (by
|
|
`Google Caja <https://developers.google.com/caja>`__), all Javascript
|
|
(including click event handlers, etc.) and CSS will be stripped.
|
|
|
|
We plan to provide a mechanism for notebook themes, but in the meantime
|
|
styling the notebook can only be done via either ``custom.css`` or CSS
|
|
in HTML output. The latter only have an effect if the notebook is
|
|
trusted, because otherwise the output will be sanitized just like
|
|
Markdown.
|
|
|
|
Collaboration
|
|
*************
|
|
|
|
When collaborating on a notebook, people probably want to see the
|
|
outputs produced by their colleagues' most recent executions. Since each
|
|
collaborator's key will differ, this will result in each share starting
|
|
in an untrusted state. There are three basic approaches to this:
|
|
|
|
- re-run notebooks when you get them (not always viable)
|
|
- explicitly trust notebooks via ``jupyter trust`` or the notebook menu
|
|
(annoying, but easy)
|
|
- share a notebook signatures database, and use configuration dedicated to the
|
|
collaboration while working on the project.
|
|
|
|
To share a signatures database among users, you can configure:
|
|
|
|
.. code-block:: python
|
|
|
|
c.NotebookNotary.data_dir = "/path/to/signature_dir"
|
|
|
|
to specify a non-default path to the SQLite database (of notebook hashes,
|
|
essentially). We are aware that SQLite doesn't work well on NFS and we are
|
|
`working out better ways to do this <https://github.com/jupyter/notebook/issues/1782>`_.
|