Enable setting of security http headers

The following security policy headers are set:

X-XSS-Protection: 1; mode=block -- always set

X-Frame-Options: DENY is set for all pages except for the documentation
  pages, primarily because pgadmin4 loads them in an iframe which would
  break.

Content-Security-Policy: <x>-src
  Is set to allow the default of self only, then allowing scripts for
  google analytics and fonts for google fonts. Images are allowed from everywhere.
  frame-ancestors 'none' is set by the same rules as X-Frame-Options

This also adds a decorator for @script_sources to have a single view
allow extra sources, and this is used for recaptcha. A generic decorator
is also made for other types of exclusions, though we don't have any at
this point.

If the setting SECURITY_POLICY_REPORT_ONLY is set to True then the policy
will be report-only and not enforced (for testing), otherwise enforcing
mode is enabled.

The setting SECURITY_POLICY_REPORT_URI sets where to send security
policy reports, if any.
This commit is contained in:
Magnus Hagander
2018-12-20 16:50:24 +01:00
parent 48db40f71e
commit d36ea4a985
4 changed files with 62 additions and 2 deletions

View File

@ -1,5 +1,6 @@
import datetime
from functools import wraps
from collections import defaultdict
from django.contrib.auth.decorators import login_required as django_login_required
def nocache(fn):
@ -20,6 +21,27 @@ def cache(days=0, hours=0, minutes=0, seconds=0):
return __cache
return _cache
def allow_frames(fn):
def _allow_frames(request, *_args, **_kwargs):
resp = fn(request, *_args, **_kwargs)
resp.x_allow_frames = True
return resp
return _allow_frames
def content_sources(what, source):
def _script_sources(fn):
def __script_sources(request, *_args, **_kwargs):
resp = fn(request, *_args, **_kwargs)
if not hasattr(resp, 'x_allow_extra_sources'):
resp.x_allow_extra_sources = defaultdict(list)
resp.x_allow_extra_sources[what].append(source)
return resp
return __script_sources
return _script_sources
def script_sources(source):
return content_sources('script', source)
# A wrapped version of login_required that throws an exception if it's
# used on a path that's not under /account/.
def login_required(f):