1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
Description: check origin of websocket connection CVE-2014-3429
Origin: https://github.com/ipython/ipython/pull/4845
--- a/IPython/frontend/html/notebook/handlers.py
+++ b/IPython/frontend/html/notebook/handlers.py
@@ -16,6 +16,11 @@ Authors:
# Imports
#-----------------------------------------------------------------------------
+try:
+ from urllib.parse import urlparse # Py 3
+except ImportError:
+ from urlparse import urlparse # Py 2
+
import logging
import Cookie
import time
@@ -368,6 +373,30 @@ class KernelActionHandler(AuthenticatedH
class ZMQStreamHandler(websocket.WebSocketHandler):
+ def same_origin(self):
+ """Check to see that origin and host match in the headers."""
+
+ # The difference between version 8 and 13 is that in 8 the
+ # client sends a "Sec-Websocket-Origin" header and in 13 it's
+ # simply "Origin".
+ if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8"):
+ origin_header = self.request.headers.get("Sec-Websocket-Origin")
+ else:
+ origin_header = self.request.headers.get("Origin")
+
+ host = self.request.headers.get("Host")
+
+ # If no header is provided, assume we can't verify origin
+ if(origin_header is None or host is None):
+ return False
+
+ parsed_origin = urlparse(origin_header)
+ origin = parsed_origin.netloc
+
+ # Check to see that origin matches host directly, including ports
+ return origin == host
+
+
def _reserialize_reply(self, msg_list):
"""Reserialize a reply message using JSON.
@@ -409,6 +438,11 @@ class ZMQStreamHandler(websocket.WebSock
class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
def open(self, kernel_id):
+ # Check to see that origin matches host directly, including ports
+ if not self.same_origin():
+ self.log.warn("Cross Origin WebSocket Attempt.")
+ raise web.HTTPError(404)
+
self.kernel_id = kernel_id.decode('ascii')
try:
cfg = self.application.ipython_app.config
|