From 3a38f6b147df713be02719cf3ae583650df13f8b Mon Sep 17 00:00:00 2001 From: navnath gadakh Date: Mon, 9 Nov 2020 12:35:19 +0530 Subject: [PATCH] Added ALLOWED_HOSTS support. refs #5919 --- web/config.py | 8 ++++++++ web/pgadmin/__init__.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/web/config.py b/web/config.py index 6dd26be20..4acfa691d 100644 --- a/web/config.py +++ b/web/config.py @@ -183,6 +183,14 @@ X_CONTENT_TYPE_OPTIONS = "nosniff" # response contains the same data. e.g. '1; mode=block' X_XSS_PROTECTION = "1; mode=block" +# This param is used to validate ALLOWED_HOSTS for the application +# This will be used to avoid Host Header Injection attack +# ALLOWED_HOSTS = ['225.0.0.0/8', '226.0.0.0/7', '228.0.0.0/6'] +# ALLOWED_HOSTS = ['127.0.0.1', '192.168.0.1'] +# if ALLOWED_HOSTS= [] then it will accept all ips (and application will be +# vulnerable to Host Header Injection attack) +ALLOWED_HOSTS = [] + # Hashing algorithm used for password storage SECURITY_PASSWORD_HASH = 'pbkdf2_sha512' diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 4ee836da4..bffdb4375 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -13,6 +13,7 @@ import logging import os import sys import re +import ipaddress from types import MethodType from collections import defaultdict from importlib import import_module @@ -621,6 +622,41 @@ def create_app(app_name=None): app.register_blueprint(module) app.register_logout_hook(module) + @app.before_request + def limit_host_addr(): + """ + This function validate the hosts from ALLOWED_HOSTS before allowing + HTTP request to avoid Host Header Injection attack + :return: None/JSON response with 403 HTTP status code + """ + client_host = str(request.host).split(':')[0] + valid = True + allowed_hosts = config.ALLOWED_HOSTS + + if len(allowed_hosts) != 0: + regex = re.compile( + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:/\d{1,2}|)') + # Create separate list for ip addresses and host names + ip_set = list(filter(lambda ip: regex.match(ip), allowed_hosts)) + host_set = list(filter(lambda ip: not regex.match(ip), + allowed_hosts)) + is_ip = regex.match(client_host) + if is_ip: + ip_address = [] + for ip in ip_set: + ip_address.extend(list(ipaddress.ip_network(ip))) + valid = ip_address.__contains__( + ipaddress.ip_address(client_host) + ) + else: + valid = host_set.__contains__(client_host) + + if not valid: + return make_json_response( + status=403, success=0, + errormsg=_("403 FORBIDDEN") + ) + ########################################################################## # Handle the desktop login ##########################################################################