Thank you Dave for the suggestion.
Please find the attached updated patch to make HSTS by default disabled and
conditional based on flag.
Regards,
Ganesh Jaybhay
On Mon, Oct 19, 2020 at 5:38 PM Dave Page wrote:
> Hi
>
> On Mon, Oct 19, 2020 at 1:01 PM Ganesh Jaybhay <
> ganesh.jayb...@enterprisedb.com> wrote:
>
>> Hi Hackers,
>>
>> Please find the attached patch to fix the below security issues:
>>
>>- Host Header Injection - Added ALLOWED_HOSTS list to limit host
>>address
>>- Lack of Content Security Policy (CSP) - Added security header
>>- Lack of Protection Mechanisms - HSTS - Added security header
>>- Lack of Cookie Attribute – Secure : Kept as False as secure limits
>>cookies to HTTPS traffic only.
>>- Information Disclosure – Web Server / Development Framework
>>VersionDescription: Kept as hard coded 'Python' instead of exposing
>>wsgi/python/gunicorn version info.
>>
>> Please review and let me know if I have missed anything.
>>
>
> I took a very quick look at this, and one thing that immediately stood out
> is that HSTS should definitely not be enabled by default. That can make
> dev/test/redeploy extremely difficult.
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>
diff --git a/Dockerfile b/Dockerfile
index 38c1310..3f5d504 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -81,7 +81,8 @@ RUN apk add --no-cache \
flask_gravatar \
flask_migrate \
simplejson \
-cryptography
+cryptography \
+netaddr
# Copy the docs from the local tree. Explicitly remove any existing builds that
# may be present
@@ -177,6 +178,7 @@ RUN ln -sf /usr/lib/libpq.so.5.12 /usr/lib/libpq.so.5
# Copy the runner script
COPY pkg/docker/run_pgadmin.py /pgadmin4
+COPY pkg/docker/gunicorn_config.py /pgadmin4
COPY pkg/docker/entrypoint.sh /entrypoint.sh
# Precompile and optimize python code to save time and space on startup
diff --git a/pkg/docker/entrypoint.sh b/pkg/docker/entrypoint.sh
index 5a482c7..93d809f 100755
--- a/pkg/docker/entrypoint.sh
+++ b/pkg/docker/entrypoint.sh
@@ -58,7 +58,7 @@ TIMEOUT=$(cd /pgadmin4 && python -c 'import config; print(config.SESSION_EXPIRAT
# Using --threads to have multi-threaded single-process worker
if [ ! -z ${PGADMIN_ENABLE_TLS} ]; then
-exec gunicorn --timeout ${TIMEOUT} --bind ${PGADMIN_LISTEN_ADDRESS:-[::]}:${PGADMIN_LISTEN_PORT:-443} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile ${GUNICORN_ACCESS_LOGFILE:--} --keyfile /certs/server.key --certfile /certs/server.cert run_pgadmin:app
+exec gunicorn --timeout ${TIMEOUT} --bind ${PGADMIN_LISTEN_ADDRESS:-[::]}:${PGADMIN_LISTEN_PORT:-443} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile ${GUNICORN_ACCESS_LOGFILE:--} --keyfile /certs/server.key --certfile /certs/server.cert -c gunicorn_config.py run_pgadmin:app
else
-exec gunicorn --timeout ${TIMEOUT} --bind ${PGADMIN_LISTEN_ADDRESS:-[::]}:${PGADMIN_LISTEN_PORT:-80} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile ${GUNICORN_ACCESS_LOGFILE:--} run_pgadmin:app
+exec gunicorn --timeout ${TIMEOUT} --bind ${PGADMIN_LISTEN_ADDRESS:-[::]}:${PGADMIN_LISTEN_PORT:-80} -w 1 --threads ${GUNICORN_THREADS:-25} --access-logfile ${GUNICORN_ACCESS_LOGFILE:--} -c gunicorn_config.py run_pgadmin:app
fi
diff --git a/pkg/docker/gunicorn_config.py b/pkg/docker/gunicorn_config.py
new file mode 100644
index 000..513c889
--- /dev/null
+++ b/pkg/docker/gunicorn_config.py
@@ -0,0 +1,2 @@
+import gunicorn
+gunicorn.SERVER_SOFTWARE = 'Python'
diff --git a/requirements.txt b/requirements.txt
index a5815a3..dbb0083 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -41,4 +41,5 @@ Flask-Security-Too>=3.0.0
bcrypt<=3.1.7
cryptography<=3.0
sshtunnel>=0.1.5
+netaddr==0.8.0
ldap3>=2.5.1
diff --git a/web/config.py b/web/config.py
index 702e73f..b893e35 100644
--- a/web/config.py
+++ b/web/config.py
@@ -143,12 +143,57 @@ DEFAULT_SERVER = '127.0.0.1'
# environment by the runtime
DEFAULT_SERVER_PORT = 5050
+# This param is used to validate ALLOWED_HOSTS for the application
+# This will be used to avoid Host Header Injection attack
+# For how to set ALLOWED_HOSTS see netaddr library
+# For more details https://netaddr.readthedocs.io/en/latest/tutorial_03.html
+# e.g. ALLOWED_HOSTS = ['192.0.2.0/28', '::192.0.2.0/124']
+# 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 = []
+
+# This param is used to override the default web server information about
+# the web technology and the frameworks being used in the application
+# An attacker could use this information to fingerprint underlying operating
+# system and research known exploits for the specific version of
+# software in use
+WEB_SERVER = 'Python'
+
# Enable X-Fr