Reputation: 2502
I'm looking to make a new Wagtail site production-ready and have used some Django security middleware settings such as SECURE_BROWSER_XSS_FILTER
and SECURE_HSTS_SECONDS
.
One HTTP header which doesn't seem to be provided for in the security middleware is Expect-CT. I'd like this header to (preferably conditionally on (a) setting(s) in the production.py
settings file) have a value like:
max-age=31536000, enforce, report-uri="https://username.report-uri.com/r/d/ct/enforce"
What would be a good way to implement this and other custom HTTP headers in Wagtail?
I have looked at the existing security middleware and tried to create my own middleware in a file within my Wagtail project, but am not sure how to reference a file/module within my project in the base.py
file. (I'm currently a Wagtail/Django/Python beginner.) Thanks.
Edit: I expect it might be worth me attempting a pull request to the security middleware, but adding custom headers to a site on a per-project/ad-hoc basis would be something I'd like to be able to do.
Upvotes: 4
Views: 876
Reputation: 2502
My issue was that I wasn't aware the module path relates directly to the filename.
The following middleware creates and adds the header based on settings.
my_project
├── my_app
│ ├── settings
│ │ ├── base.py
│ │ ├── production.py
│ ├── middleware.py
my_app/settings/base.py
MIDDLEWARE = [
# ...
'my_app.middleware.CustomHttpHeadersMiddleware',
]
my_app/middleware.py
import logging
from django.conf import settings
class CustomHttpHeadersMiddleware:
def __init__(self, get_response):
self.get_response = get_response
try:
self.expect_ct = settings.CUSTOM_SECURE_EXPECT_CT
except AttributeError:
self.expect_ct = False
def __call__(self, request):
response = self.get_response(request)
if self.expect_ct:
response['Expect-CT'] = self.__expect_ct_header_value()
return response
def __expect_ct_header_value(self):
logger = logging.getLogger(__name__)
try:
max_age = settings.CUSTOM_SECURE_EXPECT_CT_MAX_AGE
except AttributeError:
max_age = 60 * 60 * 24 # 1 day
logger.warning('CUSTOM_SECURE_EXPECT_CT setting is True but CUSTOM_SECURE_EXPECT_CT_MAX_AGE setting is not set. Default of %s applied.' % max_age)
try:
enforce = settings.CUSTOM_SECURE_EXPECT_CT_ENFORCE
except AttributeError:
enforce = False
logger.warning('CUSTOM_SECURE_EXPECT_CT setting is True but CUSTOM_SECURE_EXPECT_CT_ENFORCE setting is not set. Default of False applied.')
try:
report_uri = settings.CUSTOM_SECURE_EXPECT_CT_REPORT_URI
except AttributeError:
report_uri = False
logger.warning('CUSTOM_SECURE_EXPECT_CT setting is True but CUSTOM_SECURE_EXPECT_CT_REPORT_URI setting is not set. Default of False applied.')
value = 'max-age=%s' % max_age
if enforce:
value += ', enforce'
if report_uri:
value += ', report-uri="%s"' % report_uri
return value
my_app/settings/production.py
# Custom middleware.
CUSTOM_SECURE_EXPECT_CT = True
CUSTOM_SECURE_EXPECT_CT_MAX_AGE = 60 * 60 * 24 * 365 # 1 year
CUSTOM_SECURE_EXPECT_CT_ENFORCE = True
CUSTOM_SECURE_EXPECT_CT_REPORT_URI = 'https://username.report-uri.com/r/d/ct/enforce'
Upvotes: 2