Quick start

Danger

The default security settings set by this package are aggressive, especially concerning HSTS. Do not deploy in a production environment with default settings unless you are certain your server configuration is compatible.

Default configuration

To apply default security headers to all responses:

  1. Installation

    1. From pip

      pip install django-security-headers
      
    2. To access the scan function from httpobs, add the following to your project’s dev requirements

      -e git+https://github.com/jsumnerPhD/http-observatory#egg=httpobs
      
  2. Add the csp and security_headers middlewares. For Django 1.11, also add the samesite middleware

    MIDDLEWARES = [
      "django.middleware.security.SecurityMiddleware",
      "csp.middleware.CSPMiddleware",
      "security_headers.middleware.extra_security_headers_middleware",
      "django_cookies_samesite.middleware.CookiesSameSite", # Not needed for Django 2.2
       ...
    ]
    
  3. Add security_headers to your INSTALLED_APPS.

    INSTALLED_APPS = [
      ...
      "security_headers",
      ...
    ]
    

This will expose a simple admin interface for specifying safe domains.

  1. Import default security settings in your project settings.py

    from security_headers.defaults import *  # noqa F403
    

Optional configuration

If you included step 1b, you can add a scan link to urls.py. Accessing this link will run a scan against https://127.0.0.1:8000/<path> where the path is determined from reversing url_name. Note that the sslserver must be running in parallel to the request.

from security_headers.views import scan_url

if settings.DEBUG:
    urlpatterns += i18n_patterns(
        url(r"^security/(?P<url_name>[\w-]+)/", scan_url, name="scan")
    )

For newer Django syntax

urlpatterns += [path("security/<slug:url_name>/", scan_url, name="scan")]

To access template tags provided by django-csp, add csp to INSTALLED_APPS

INSTALLED_APPS = [
  ...
  "security_headers",
  "csp",
  ...
]

To use the sslserver (provided by django-sslserver through ./manage.py runsslserver)

INSTALLED_APPS = [
  ...
  "security_headers",
  "csp",
  "sslserver",
  ...
]

Development settings

During development, you will need to overwrite some default settings if not using the ssl server. At the very end of your settings.py file, include (this is conveniently done through an imported local_settings.py):

if "runsslserver" in sys.argv:
    SSL_CONTEXT = True
    SECURE_HSTS_SECONDS = 3600
else:
    SSL_CONTEXT = False
    SECURE_HSTS_SECONDS = 0
    CSRF_COOKIE_NAME = 'csrftoken'

CSRF_COOKIE_SECURE = SSL_CONTEXT
SECURE_SSL_REDIRECT = SSL_CONTEXT
SESSION_COOKIE_SECURE = SSL_CONTEXT
CSP_UPGRADE_INSECURE_REQUESTS = SSL_CONTEXT

Reducing SECURE_HSTS_SECONDS time is also a good idea during development.

Default settings

Django settings

SECURE_HSTS_INCLUDE_SUBDOMAINS

Default: True

Warning

Activating HSTS may irreversibly break your site (for SECURE_HSTS_SECONDS) if improperly configured. Review Django’s advice regarding HSTS first!

SECURE_HSTS_PRELOAD

Default: True

Warning

Activating HSTS may irreversibly break your site (for SECURE_HSTS_SECONDS) if improperly configured. Review Django’s advice regarding HSTS first!

SECURE_HSTS_SECONDS

Default: 183 * 24 * 60 * 60

Warning

Activating HSTS may irreversibly break your site (for SECURE_HSTS_SECONDS) if improperly configured. Review Django’s advice regarding HSTS first!

Django-CSP settings

See the django-csp docs for full details.

CSP_BASE_URI

Default: ["'none'"]

CSP_DEFAULT_SRC

Default: ["'self'"]

CSP_FONT_SRC

Default: ["'self'"]

CSP_FORM_ACTION

Default: ["'self'"]

CSP_FRAME_ANCESTORS

Default: ["'none'"]

CSP_FRAME_SRC

Default: ["*"]

CSP_IMG_SRC

Default: ["*", "data:"]

CSP_MEDIA_SRC

Default: ["*", "data:"]

CSP_SCRIPT_SRC

Default: ["'self'"]

CSP_STYLE_SRC

Default: ["'self'"]

CSP_INCLUDE_NONCE_IN

Default: ["script-src", "style-src"]

CSP_UPGRADE_INSECURE_REQUESTS

Default: True

CSP_BLOCK_ALL_MIXED_CONTENT

Default: True

CSP_REPORT_PERCENTAGE

Default: 0.1

Middleware settings

REFERRER_POLICY

Default: same-origin

Tip

See the Mozilla Http Observatory recommendations regarding the referrer-policy as well as Scott Helme’s discussion.

FEATURE_POLICY

Default:

[
    "autoplay 'none'",
    "camera 'none'",
    "display-capture 'none'",
    "document-domain 'none'",
    "encrypted-media 'none'",
    "fullscreen *",
    "geolocation 'none'",
    "microphone 'none'",
    "midi 'none'",
    "payment 'none'",
    "vr *",
]

Tip

See Scott Helme’s discussion on the new feature policy header.

FRAMING_ALLOWED_FROM

Default: deny

Safe domains for X-FRAME-OPTIONS can be specified two ways:

  1. Through the admin interface, or
  2. In settings.py by assigning a list to FRAMING_ALLOWED_FROM. This list supersedes any database entries: if this list is set, domains entered through admin are ignored. To allow all domains, set FRAMING_ALLOWED_FROM = ["*"]

Middleware

security_headers.middleware.extra_security_headers_middleware(get_response)

Sets security headers specified in SETTINGS on all responses.

Models

class security_headers.models.FramingAllowedFrom(*args, **kwargs)

Domains from which framing is allowed.

exception DoesNotExist
exception MultipleObjectsReturned

Contributing

  1. Install development requirements

    pip install -r requirements/dev-requirements.txt
    
  2. Install pre-commit hooks

    pre-commit install
    
  3. To run localserver

    python security_headers.py runserver
    
  4. To get http-observatory scan report, start a separate secure localhost (at 127.0.0.1:8000) to enable https and then navigate to the /scan/<name of url> from runserver

    python security_headers.py runsslserver
    
  5. To run test suite

    pytest
    
  6. To test build

    tox
    
  7. To make docs locally

    cd docs
    make html