Skip to content

Commit

Permalink
Forces headers in Apache config
Browse files Browse the repository at this point in the history
Based on the comments in [0], ensures that headers are always sent to
the client, regardless of HTTP status code. We do this by unsetting the
header if the request was successful, then forcing the same header with
desired value using the "always" conditional.

[0] https://httpd.apache.org/docs/current/mod/mod_headers.html
  • Loading branch information
Conor Schaefer committed Feb 23, 2021
1 parent 3885fcb commit b7c0ef1
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ XSendFilePath /var/lib/securedrop/store/
XSendFilePath /var/lib/securedrop/tmp/

Header edit Set-Cookie ^(.*)$ $1;HttpOnly
Header always append X-Frame-Options: DENY
Header set Referrer-Policy "no-referrer"
Header set X-XSS-Protection: "1; mode=block"
Header set X-Content-Type-Options: nosniff
Header set X-Download-Options: noopen
Header set Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

Header onsuccess unset X-Frame-Options
Header always set X-Frame-Options "DENY"
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "no-referrer"
Header onsuccess unset X-XSS-Protection
Header always set X-XSS-Protection "1; mode=block"

Header onsuccess unset X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"
Header onsuccess unset X-Download-Options
Header always set X-Download-Options "noopen"
Header onsuccess unset Content-Security-Policy
Header always set Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

# Limit the max submitted size of requests.
LimitRequestBody 524288000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,21 @@ XSendFile Off
Header edit Set-Cookie ^(.*)$ $1;HttpOnly

# Don't allow SecureDrop to be framed. Clickjacking mitigation.
Header always append X-Frame-Options: DENY

Header set X-XSS-Protection: "1; mode=block"
Header set X-Content-Type-Options: nosniff
Header set Referrer-Policy "same-origin"
Header onsuccess unset X-Frame-Options
Header always set X-Frame-Options "DENY"
Header onsuccess unset Referrer-Policy
Header always set Referrer-Policy "same-origin"
Header onsuccess unset X-XSS-Protection
Header always set X-XSS-Protection "1; mode=block"

# Set a strict CSP; "default-src 'self'" prevents 3rd party subresources from
# loading and prevents inline script from executing.
Header set Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"
Header set X-Download-Options: noopen
Header onsuccess unset Content-Security-Policy
Header always set Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"
Header onsuccess unset X-Download-Options
Header always set X-Download-Options "noopen"
Header onsuccess unset X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"

Header unset Etag

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
testinfra_hosts = [securedrop_test_vars.app_hostname]


@pytest.mark.parametrize("header", securedrop_test_vars.wanted_apache_headers)
def test_apache_headers_journalist_interface(host, header):
@pytest.mark.parametrize("header, value", securedrop_test_vars.wanted_apache_headers.items())
def test_apache_headers_journalist_interface(host, header, value):
"""
Test for expected headers in Document Interface vhost config.
"""
Expand All @@ -17,8 +17,10 @@ def test_apache_headers_journalist_interface(host, header):
assert f.user == "root"
assert f.group == "root"
assert f.mode == 0o644
header_regex = "^{}$".format(re.escape(header))
assert re.search(header_regex, f.content_string, re.M)
header_unset = "Header onsuccess unset {}".format(header)
assert f.contains(header_unset)
header_set = "Header always set {} \"{}\"".format(header, value)
assert f.contains(header_set)


# declare journalist-specific Apache configs
Expand All @@ -27,7 +29,8 @@ def test_apache_headers_journalist_interface(host, header):
securedrop_test_vars.apache_listening_address),
"WSGIDaemonProcess journalist processes=2 threads=30 display-name=%{{GROUP}} python-path={}".format( # noqa
securedrop_test_vars.securedrop_code),
'Header set Referrer-Policy "no-referrer"',
'Header onsuccess unset Referrer-Policy',
'Header always set Referrer-Policy "no-referrer"',
(
'WSGIScriptAlias / /var/www/journalist.wsgi '
'process-group=journalist application-group=journalist'
Expand Down
13 changes: 8 additions & 5 deletions molecule/testinfra/app/apache/test_apache_source_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
testinfra_hosts = [securedrop_test_vars.app_hostname]


@pytest.mark.parametrize("header", securedrop_test_vars.wanted_apache_headers)
def test_apache_headers_source_interface(host, header):
@pytest.mark.parametrize("header, value", securedrop_test_vars.wanted_apache_headers.items())
def test_apache_headers_source_interface(host, header, value):
"""
Test for expected headers in Source Interface vhost config.
"""
Expand All @@ -17,8 +17,10 @@ def test_apache_headers_source_interface(host, header):
assert f.user == "root"
assert f.group == "root"
assert f.mode == 0o644
header_regex = "^{}$".format(re.escape(header))
assert re.search(header_regex, f.content_string, re.M)
header_unset = "Header onsuccess unset {}".format(header)
assert f.contains(header_unset)
header_set = "Header always set {} \"{}\"".format(header, value)
assert f.contains(header_set)


@pytest.mark.parametrize("apache_opt", [
Expand All @@ -29,7 +31,8 @@ def test_apache_headers_source_interface(host, header):
'WSGIProcessGroup source',
'WSGIScriptAlias / /var/www/source.wsgi',
'Header set Cache-Control "no-store"',
'Header set Referrer-Policy "same-origin"',
'Header onsuccess unset Referrer-Policy',
'Header always set Referrer-Policy "same-origin"',
'Header unset Etag',
"Alias /static {}/static".format(securedrop_test_vars.securedrop_code),
'XSendFile Off',
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/app-qubes-staging.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: "{{ securedrop_venv }}/bin"
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/app-staging.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: /opt/venvs/securedrop-app-code/bin
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/prod.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: "/opt/venvs/securedrop-app-code/bin"
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/prodVM.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: "/opt/venvs/securedrop-app-code/bin"
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/qubes-staging.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: "/opt/venvs/securedrop-app-code/bin"
Expand Down
11 changes: 5 additions & 6 deletions molecule/testinfra/vars/staging.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
# Testinfra vars file for app-staigng.
wanted_apache_headers:
- 'Header edit Set-Cookie ^(.*)$ $1;HttpOnly'
- 'Header always append X-Frame-Options: DENY'
- 'Header set X-XSS-Protection: "1; mode=block"'
- 'Header set X-Content-Type-Options: nosniff'
- 'Header set X-Download-Options: noopen'
- "Header set Content-Security-Policy: \"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';\""
X-Frame-Options: DENY
X-XSS-Protection: "1; mode=block"
X-Content-Type-Options: nosniff
X-Download-Options: noopen
Content-Security-Policy: "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';"

securedrop_venv: /opt/venvs/securedrop-app-code
securedrop_venv_bin: /opt/venvs/securedrop-app-code/bin
Expand Down

0 comments on commit b7c0ef1

Please sign in to comment.