Show More
@@ -1,148 +1,146 b'' | |||||
1 | Security in IPython notebooks |
|
1 | Security in IPython notebooks | |
2 | ============================= |
|
2 | ============================= | |
3 |
|
3 | |||
4 | As IPython notebooks become more popular for sharing and collaboration, |
|
4 | As IPython notebooks become more popular for sharing and collaboration, | |
5 | the potential for malicious people to attempt to exploit the notebook |
|
5 | the potential for malicious people to attempt to exploit the notebook | |
6 | for their nefarious purposes increases. IPython 2.0 introduces a |
|
6 | for their nefarious purposes increases. IPython 2.0 introduces a | |
7 | security model to prevent execution of untrusted code without explicit |
|
7 | security model to prevent execution of untrusted code without explicit | |
8 | user input. |
|
8 | user input. | |
9 |
|
9 | |||
10 | The problem |
|
10 | The problem | |
11 | ----------- |
|
11 | ----------- | |
12 |
|
12 | |||
13 | The whole point of IPython is arbitrary code execution. We have no |
|
13 | The whole point of IPython is arbitrary code execution. We have no | |
14 | desire to limit what can be done with a notebook, which would negatively |
|
14 | desire to limit what can be done with a notebook, which would negatively | |
15 | impact its utility. |
|
15 | impact its utility. | |
16 |
|
16 | |||
17 | Unlike other programs, an IPython notebook document includes output. |
|
17 | Unlike other programs, an IPython notebook document includes output. | |
18 | Unlike other documents, that output exists in a context that can execute |
|
18 | Unlike other documents, that output exists in a context that can execute | |
19 | code (via Javascript). |
|
19 | code (via Javascript). | |
20 |
|
20 | |||
21 | The security problem we need to solve is that no code should execute |
|
21 | The security problem we need to solve is that no code should execute | |
22 | just because a user has **opened** a notebook that **they did not |
|
22 | just because a user has **opened** a notebook that **they did not | |
23 | write**. Like any other program, once a user decides to execute code in |
|
23 | write**. Like any other program, once a user decides to execute code in | |
24 | a notebook, it is considered trusted, and should be allowed to do |
|
24 | a notebook, it is considered trusted, and should be allowed to do | |
25 | anything. |
|
25 | anything. | |
26 |
|
26 | |||
27 | Our security model |
|
27 | Our security model | |
28 | ------------------ |
|
28 | ------------------ | |
29 |
|
29 | |||
30 | - Untrusted HTML is always sanitized |
|
30 | - Untrusted HTML is always sanitized | |
31 | - Untrusted Javascript is never executed |
|
31 | - Untrusted Javascript is never executed | |
32 | - HTML and Javascript in Markdown cells are never trusted |
|
32 | - HTML and Javascript in Markdown cells are never trusted | |
33 | - **Outputs** generated by the user are trusted |
|
33 | - **Outputs** generated by the user are trusted | |
34 | - Any other HTML or Javascript (in Markdown cells, output generated by |
|
34 | - Any other HTML or Javascript (in Markdown cells, output generated by | |
35 | others) is never trusted |
|
35 | others) is never trusted | |
36 | - The central question of trust is "Did the current user do this?" |
|
36 | - The central question of trust is "Did the current user do this?" | |
37 |
|
37 | |||
38 | The details of trust |
|
38 | The details of trust | |
39 | -------------------- |
|
39 | -------------------- | |
40 |
|
40 | |||
41 | IPython notebooks store a signature in metadata, which is used to answer |
|
41 | IPython notebooks store a signature in metadata, which is used to answer | |
42 | the question "Did the current user do this?" |
|
42 | the question "Did the current user do this?" | |
43 |
|
43 | |||
44 | This signature is a digest of the notebooks contents plus a secret key, |
|
44 | This signature is a digest of the notebooks contents plus a secret key, | |
45 | known only to the user. The secret key is a user-only readable file in |
|
45 | known only to the user. The secret key is a user-only readable file in | |
46 | the IPython profile's security directory. By default, this is:: |
|
46 | the IPython profile's security directory. By default, this is:: | |
47 |
|
47 | |||
48 | ~/.ipython/profile_default/security/notebook_secret |
|
48 | ~/.ipython/profile_default/security/notebook_secret | |
49 |
|
49 | |||
50 | When a notebook is opened by a user, the server computes a signature |
|
50 | When a notebook is opened by a user, the server computes a signature | |
51 | with the user's key, and compares it with the signature stored in the |
|
51 | with the user's key, and compares it with the signature stored in the | |
52 | notebook's metadata. If the signature matches, HTML and Javascript |
|
52 | notebook's metadata. If the signature matches, HTML and Javascript | |
53 | output in the notebook will be trusted at load, otherwise it will be |
|
53 | output in the notebook will be trusted at load, otherwise it will be | |
54 | untrusted. |
|
54 | untrusted. | |
55 |
|
55 | |||
56 | Any output generated during an interactive session is trusted. |
|
56 | Any output generated during an interactive session is trusted. | |
57 |
|
57 | |||
58 | Updating trust |
|
58 | Updating trust | |
59 | ************** |
|
59 | ************** | |
60 |
|
60 | |||
61 | A notebook's trust is updated when the notebook is saved. If there are |
|
61 | A notebook's trust is updated when the notebook is saved. If there are | |
62 | any untrusted outputs still in the notebook, the notebook will not be |
|
62 | any untrusted outputs still in the notebook, the notebook will not be | |
63 | trusted, and no signature will be stored. If all untrusted outputs have |
|
63 | trusted, and no signature will be stored. If all untrusted outputs have | |
64 | been removed (either via ``Clear Output`` or re-execution), then the |
|
64 | been removed (either via ``Clear Output`` or re-execution), then the | |
65 | notebook will become trusted. |
|
65 | notebook will become trusted. | |
66 |
|
66 | |||
67 | While trust is updated per output, this is only for the duration of a |
|
67 | While trust is updated per output, this is only for the duration of a | |
68 | single session. A notebook file on disk is either trusted or not in its |
|
68 | single session. A notebook file on disk is either trusted or not in its | |
69 | entirety. |
|
69 | entirety. | |
70 |
|
70 | |||
71 | Explicit trust |
|
71 | Explicit trust | |
72 | ************** |
|
72 | ************** | |
73 |
|
73 | |||
74 | Sometimes re-executing a notebook to generate trusted output is not an |
|
74 | Sometimes re-executing a notebook to generate trusted output is not an | |
75 | option, either because dependencies are unavailable, or it would take a |
|
75 | option, either because dependencies are unavailable, or it would take a | |
76 | long time. Users can explicitly trust a notebook in two ways: |
|
76 | long time. Users can explicitly trust a notebook in two ways: | |
77 |
|
77 | |||
78 | - At the command-line, with:: |
|
78 | - At the command-line, with:: | |
79 |
|
79 | |||
80 | ipython trust /path/to/notebook.ipynb |
|
80 | ipython trust /path/to/notebook.ipynb | |
81 |
|
81 | |||
82 | - After loading the untrusted notebook, with ``File / Trust Notebook`` |
|
82 | - After loading the untrusted notebook, with ``File / Trust Notebook`` | |
83 |
|
83 | |||
84 | These two methods simply load the notebook, compute a new signature with |
|
84 | These two methods simply load the notebook, compute a new signature with | |
85 | the user's key, and then store the newly signed notebook. |
|
85 | the user's key, and then store the newly signed notebook. | |
86 |
|
86 | |||
87 | Reporting security issues |
|
87 | Reporting security issues | |
88 | ------------------------- |
|
88 | ------------------------- | |
89 |
|
89 | |||
90 | If you find a security vulnerability in IPython, either a failure of the |
|
90 | If you find a security vulnerability in IPython, either a failure of the | |
91 | code to properly implement the model described here, or a failure of the |
|
91 | code to properly implement the model described here, or a failure of the | |
92 | model itself, please report it to security@ipython.org. |
|
92 | model itself, please report it to security@ipython.org. | |
93 |
|
93 | |||
94 | If you prefer to encrypt your security reports, |
|
94 | If you prefer to encrypt your security reports, | |
95 |
you can use this PGP public key |
|
95 | you can use :download:`this PGP public key <ipython_security.asc>`. | |
96 |
|
||||
97 | .. literalinclude:: ipython_security.asc |
|
|||
98 |
|
96 | |||
99 | Affected use cases |
|
97 | Affected use cases | |
100 | ------------------ |
|
98 | ------------------ | |
101 |
|
99 | |||
102 | Some use cases that work in IPython 1.0 will become less convenient in |
|
100 | Some use cases that work in IPython 1.0 will become less convenient in | |
103 | 2.0 as a result of the security changes. We do our best to minimize |
|
101 | 2.0 as a result of the security changes. We do our best to minimize | |
104 | these annoyance, but security is always at odds with convenience. |
|
102 | these annoyance, but security is always at odds with convenience. | |
105 |
|
103 | |||
106 | Javascript and CSS in Markdown cells |
|
104 | Javascript and CSS in Markdown cells | |
107 | ************************************ |
|
105 | ************************************ | |
108 |
|
106 | |||
109 | While never officially supported, it had become common practice to put |
|
107 | While never officially supported, it had become common practice to put | |
110 | hidden Javascript or CSS styling in Markdown cells, so that they would |
|
108 | hidden Javascript or CSS styling in Markdown cells, so that they would | |
111 | not be visible on the page. Since Markdown cells are now sanitized (by |
|
109 | not be visible on the page. Since Markdown cells are now sanitized (by | |
112 | `Google Caja <https://developers.google.com/caja>`__), all Javascript |
|
110 | `Google Caja <https://developers.google.com/caja>`__), all Javascript | |
113 | (including click event handlers, etc.) and CSS will be stripped. |
|
111 | (including click event handlers, etc.) and CSS will be stripped. | |
114 |
|
112 | |||
115 | We plan to provide a mechanism for notebook themes, but in the meantime |
|
113 | We plan to provide a mechanism for notebook themes, but in the meantime | |
116 | styling the notebook can only be done via either ``custom.css`` or CSS |
|
114 | styling the notebook can only be done via either ``custom.css`` or CSS | |
117 | in HTML output. The latter only have an effect if the notebook is |
|
115 | in HTML output. The latter only have an effect if the notebook is | |
118 | trusted, because otherwise the output will be sanitized just like |
|
116 | trusted, because otherwise the output will be sanitized just like | |
119 | Markdown. |
|
117 | Markdown. | |
120 |
|
118 | |||
121 | Collaboration |
|
119 | Collaboration | |
122 | ************* |
|
120 | ************* | |
123 |
|
121 | |||
124 | When collaborating on a notebook, people probably want to see the |
|
122 | When collaborating on a notebook, people probably want to see the | |
125 | outputs produced by their colleagues' most recent executions. Since each |
|
123 | outputs produced by their colleagues' most recent executions. Since each | |
126 | collaborator's key will differ, this will result in each share starting |
|
124 | collaborator's key will differ, this will result in each share starting | |
127 | in an untrusted state. There are three basic approaches to this: |
|
125 | in an untrusted state. There are three basic approaches to this: | |
128 |
|
126 | |||
129 | - re-run notebooks when you get them (not always viable) |
|
127 | - re-run notebooks when you get them (not always viable) | |
130 | - explicitly trust notebooks via ``ipython trust`` or the notebook menu |
|
128 | - explicitly trust notebooks via ``ipython trust`` or the notebook menu | |
131 | (annoying, but easy) |
|
129 | (annoying, but easy) | |
132 | - share a notebook secret, and use an IPython profile dedicated to the |
|
130 | - share a notebook secret, and use an IPython profile dedicated to the | |
133 | collaboration while working on the project. |
|
131 | collaboration while working on the project. | |
134 |
|
132 | |||
135 | Multiple profiles or machines |
|
133 | Multiple profiles or machines | |
136 | ***************************** |
|
134 | ***************************** | |
137 |
|
135 | |||
138 | Since the notebook secret is stored in a profile directory by default, |
|
136 | Since the notebook secret is stored in a profile directory by default, | |
139 | opening a notebook with a different profile or on a different machine |
|
137 | opening a notebook with a different profile or on a different machine | |
140 | will result in a different key, and thus be untrusted. The only current |
|
138 | will result in a different key, and thus be untrusted. The only current | |
141 | way to address this is by sharing the notebook secret. This can be |
|
139 | way to address this is by sharing the notebook secret. This can be | |
142 | facilitated by setting the configurable: |
|
140 | facilitated by setting the configurable: | |
143 |
|
141 | |||
144 | .. sourcecode:: python |
|
142 | .. sourcecode:: python | |
145 |
|
143 | |||
146 | c.NotebookApp.secret_file = "/path/to/notebook_secret" |
|
144 | c.NotebookApp.secret_file = "/path/to/notebook_secret" | |
147 |
|
145 | |||
148 | in each profile, and only sharing the secret once per machine. |
|
146 | in each profile, and only sharing the secret once per machine. |
General Comments 0
You need to be logged in to leave comments.
Login now