##// END OF EJS Templates
Merge pull request #7016 from rgbkrk/csp...
Min RK -
r19161:d56bcc10 merge
parent child Browse files
Show More
@@ -0,0 +1,4 b''
1 # URI for the CSP Report. Included here to prevent a cyclic dependency.
2 # csp_report_uri is needed both by the BaseHandler (for setting the report-uri)
3 # and by the CSPReportHandler (which depends on the BaseHandler).
4 csp_report_uri = r"/api/security/csp-report"
@@ -0,0 +1,23 b''
1 """Tornado handlers for security logging."""
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
6 from tornado import gen, web
7
8 from ...base.handlers import IPythonHandler, json_errors
9 from . import csp_report_uri
10
11 class CSPReportHandler(IPythonHandler):
12 '''Accepts a content security policy violation report'''
13 @web.authenticated
14 @json_errors
15 def post(self):
16 '''Log a content security policy violation report'''
17 csp_report = self.get_json_body()
18 self.log.warn("Content security violation: %s",
19 self.request.body.decode('utf8', 'replace'))
20
21 default_handlers = [
22 (csp_report_uri, CSPReportHandler)
23 ]
@@ -32,6 +32,8 b' from IPython.utils.path import filefind'
32 from IPython.utils.py3compat import string_types
32 from IPython.utils.py3compat import string_types
33 from IPython.html.utils import is_hidden, url_path_join, url_escape
33 from IPython.html.utils import is_hidden, url_path_join, url_escape
34
34
35 from IPython.html.services.security import csp_report_uri
36
35 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
36 # Top-level handlers
38 # Top-level handlers
37 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
@@ -45,17 +47,22 b' class AuthenticatedHandler(web.RequestHandler):'
45 def set_default_headers(self):
47 def set_default_headers(self):
46 headers = self.settings.get('headers', {})
48 headers = self.settings.get('headers', {})
47
49
48 if "X-Frame-Options" not in headers:
50 if "Content-Security-Policy" not in headers:
49 headers["X-Frame-Options"] = "SAMEORIGIN"
51 headers["Content-Security-Policy"] = (
52 "frame-ancestors 'self'; "
53 # Make sure the report-uri is relative to the base_url
54 "report-uri " + url_path_join(self.base_url, csp_report_uri) + ";"
55 )
50
56
57 # Allow for overriding headers
51 for header_name,value in headers.items() :
58 for header_name,value in headers.items() :
52 try:
59 try:
53 self.set_header(header_name, value)
60 self.set_header(header_name, value)
54 except Exception:
61 except Exception as e:
55 # tornado raise Exception (not a subclass)
62 # tornado raise Exception (not a subclass)
56 # if method is unsupported (websocket and Access-Control-Allow-Origin
63 # if method is unsupported (websocket and Access-Control-Allow-Origin
57 # for example, so just ignore)
64 # for example, so just ignore)
58 pass
65 self.log.debug(e)
59
66
60 def clear_login_cookie(self):
67 def clear_login_cookie(self):
61 self.clear_cookie(self.cookie_name)
68 self.clear_cookie(self.cookie_name)
@@ -225,7 +225,7 b' class NotebookWebApplication(web.Application):'
225 handlers.extend(load_handlers('services.sessions.handlers'))
225 handlers.extend(load_handlers('services.sessions.handlers'))
226 handlers.extend(load_handlers('services.nbconvert.handlers'))
226 handlers.extend(load_handlers('services.nbconvert.handlers'))
227 handlers.extend(load_handlers('services.kernelspecs.handlers'))
227 handlers.extend(load_handlers('services.kernelspecs.handlers'))
228
228 handlers.extend(load_handlers('services.security.handlers'))
229 handlers.append(
229 handlers.append(
230 (r"/nbextensions/(.*)", FileFindHandler, {
230 (r"/nbextensions/(.*)", FileFindHandler, {
231 'path': settings['nbextensions_path'],
231 'path': settings['nbextensions_path'],
@@ -65,7 +65,10 b' class KernelAPITest(NotebookTestBase):'
65 self.assertEqual(r.status_code, 201)
65 self.assertEqual(r.status_code, 201)
66 self.assertIsInstance(kern1, dict)
66 self.assertIsInstance(kern1, dict)
67
67
68 self.assertEqual(r.headers['x-frame-options'], "SAMEORIGIN")
68 self.assertEqual(r.headers['Content-Security-Policy'], (
69 "frame-ancestors 'self'; "
70 "report-uri /api/security/csp-report;"
71 ))
69
72
70 def test_main_kernel_handler(self):
73 def test_main_kernel_handler(self):
71 # POST request
74 # POST request
@@ -75,7 +78,10 b' class KernelAPITest(NotebookTestBase):'
75 self.assertEqual(r.status_code, 201)
78 self.assertEqual(r.status_code, 201)
76 self.assertIsInstance(kern1, dict)
79 self.assertIsInstance(kern1, dict)
77
80
78 self.assertEqual(r.headers['x-frame-options'], "SAMEORIGIN")
81 self.assertEqual(r.headers['Content-Security-Policy'], (
82 "frame-ancestors 'self'; "
83 "report-uri /api/security/csp-report;"
84 ))
79
85
80 # GET request
86 # GET request
81 r = self.kern_api.list()
87 r = self.kern_api.list()
@@ -180,16 +180,42 b' Backwards incompatible changes'
180
180
181 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
181 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
182
182
183 IFrame embedding
183 Content Security Policy
184 ````````````````
184 ```````````````````````
185
185
186 The IPython Notebook and its APIs by default will only be allowed to be
186 The Content Security Policy is a web standard for adding a layer of security to
187 embedded in an iframe on the same origin.
187 detect and mitigate certain classes of attacks, including Cross Site Scripting
188 (XSS) and data injection attacks. This was introduced into the notebook to
189 ensure that the IPython Notebook and its APIs (by default) can only be embedded
190 in an iframe on the same origin.
188
191
189 To override this, set ``headers[X-Frame-Options]`` to one of
192 Override ``headers['Content-Security-Policy']`` within your notebook
193 configuration to extend for alternate domains and security settings.::
190
194
191 * DENY
195 c.NotebookApp.tornado_settings = {
192 * SAMEORIGIN
196 'headers': {
193 * ALLOW-FROM uri
197 'Content-Security-Policy': "frame-ancestors 'self'"
198 }
199 }
194
200
195 See `Mozilla's guide to X-Frame-Options <https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options>`_ for more examples.
201 Example policies::
202
203 Content-Security-Policy: default-src 'self' https://*.jupyter.org
204
205 Matches embeddings on any subdomain of jupyter.org, so long as they are served
206 over SSL.
207
208 There is a `report-uri <https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives#report-uri>`_ endpoint available for logging CSP violations, located at
209 ``/api/security/csp-report``. To use it, set ``report-uri`` as part of the CSP::
210
211 c.NotebookApp.tornado_settings = {
212 'headers': {
213 'Content-Security-Policy': "frame-ancestors 'self'; report-uri /api/security/csp-report"
214 }
215 }
216
217 It simply provides the CSP report as a warning in IPython's logs. The default
218 CSP sets this report-uri relative to the ``base_url`` (not shown above).
219
220 For a more thorough and accurate guide on Content Security Policies, check out
221 `MDN's Using Content Security Policy <https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy>`_ for more examples.
General Comments 0
You need to be logged in to leave comments. Login now