Fixed possible security issues in HTTP server + minor optimizations

parent bea52af8
......@@ -19,6 +19,7 @@ CONFIG_HTTP = {
"API_ROOT": "/restconf",
"API_ROOT_STAGING": "/restconf_staging",
"SERVER_NAME": "hyper-h2",
"UPLOAD_SIZE_LIMIT": 1,
"PORT": 8443,
"SERVER_SSL_CERT": "server.crt",
......
......@@ -169,17 +169,14 @@ def create_get_staging_api(ds: BaseDatastore):
def get_file(prot: "H2Protocol", stream_id: int, headers: OrderedDict):
# Ordinary file on filesystem
username = CertHelpers.get_field(prot.client_cert, "emailAddress")
url_split = headers[":path"].split("?")
url_path = url_split[0]
file_path = os.path.join(CONFIG_HTTP["DOC_ROOT"], url_path[1:].replace("..", "").replace("&", ""))
url_path = headers[":path"].split("?")[0]
url_path_safe = "".join(filter(lambda c: c.isalpha() or c in "/-_.", url_path)).replace("..", "").strip("/")
file_path = os.path.join(CONFIG_HTTP["DOC_ROOT"], url_path_safe)
if os.path.isdir(file_path):
file_path = os.path.join(file_path, CONFIG_HTTP["DOC_DEFAULT_NAME"])
(ctype, encoding) = mimetypes.guess_type(file_path)
if ctype is None:
ctype = "application/octet-stream"
ctype = mimetypes.guess_type(file_path)[0] or "application/octet-stream"
try:
fd = open(file_path, 'rb')
......
......@@ -6,7 +6,7 @@ from colorlog import error, warning as warn, info, debug
from typing import List, Tuple, Dict, Any, Callable
from h2.connection import H2Connection
from h2.errors import PROTOCOL_ERROR
from h2.errors import PROTOCOL_ERROR, ENHANCE_YOUR_CALM
from h2.events import DataReceived, RequestReceived, RemoteSettingsChanged, StreamEnded
import jetconf.http_handlers as handlers
......@@ -21,9 +21,10 @@ h2_handlers = None # type: HandlerList
class RequestData:
def __init__(self, headers=None, data=None):
def __init__(self, headers: OrderedDict, data: BytesIO):
self.headers = headers
self.data = data
self.data_overflow = False
class HandlerList:
......@@ -49,7 +50,7 @@ class H2Protocol(asyncio.Protocol):
def __init__(self):
self.conn = H2Connection(client_side=False)
self.transport = None
self.stream_data = {}
self.stream_data = {} # type: Dict[int, RequestData]
self.client_cert = None # type: Dict[str, Any]
def connection_made(self, transport: asyncio.Transport):
......@@ -86,13 +87,21 @@ class H2Protocol(asyncio.Protocol):
except KeyError:
self.conn.reset_stream(event.stream_id, error_code=PROTOCOL_ERROR)
else:
# Check if incoming data are not excessively large
if (stream_data.data.tell() + len(event.data)) < (CONFIG_HTTP["UPLOAD_SIZE_LIMIT"] * 1048576):
stream_data.data.write(event.data)
else:
stream_data.data_overflow = True
self.conn.reset_stream(event.stream_id, error_code=ENHANCE_YOUR_CALM)
elif isinstance(event, StreamEnded):
# Process request
try:
request_data = self.stream_data.pop(event.stream_id)
except KeyError:
self.send_empty(event.stream_id, "400", "Bad Request")
else:
if request_data.data_overflow:
self.send_empty(event.stream_id, "406", "Not Acceptable")
else:
headers = request_data.headers
body = request_data.data.getvalue().decode('utf-8')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment