Skip to main content

Standardised exception security related HTTP headers for HMLR Flask applications

Project description

Security Headers for Flask Web Applications

Convienience Flask extension for setting security headers. See below for the full list.

Note This extension will not set headers such as Content-Type, Cache-Control or Clear-Site-Data. You'll need to set those yourself when you need them.

This package depends on:

  • Flask

Usage

Instantiate it like a normal flask extension:

from landregistry.security_headers import SecurityHeaders, UIDefaultHeaders
from <somewhere> import app

# ...

headers = SecurityHeaders()
headers.init_app(app, UIDefaultHeaders)

Three default configurations are provided:

  • UIDefaultHeaders - a set of headers suited for a web front-end.
  • APIDefaultHeaders - a set of headers suited for a REST API.
  • EmptyDefaultHeaders - no defaults.

Updating an existing UI

If you have a skeleton-based UI application that pre-dates this extension's inclusion, you can easily update it to use this package as follows:

  • Add landregistry-security-headers to your requirements.
  • Remove imports and references to security_headers and content_security_policy inbuilt packages
  • Add imports and initialisation of the new extension.
  # ...
  from landregistry.healthchecks import HealthChecks
+ from landregistry.security_headers import SecurityHeaders, UIDefaultHeaders

  from server import config
  # ...
- from server.custom_extensions.content_security_policy.main import ContentSecurityPolicy
  # ...
- from server.custom_extensions.security_headers.main import SecurityHeaders
  from server.exceptions import application_error_renderer, http_error_renderer, unhandled_error_renderer

  # Create empty extension objects here
  # ...
- security_headers = SecurityHeaders()
  # ...
- content_security_policy = ContentSecurityPolicy()
  # ...
  health = HealthChecks()
+ headers = SecurityHeaders()

  def register_extensions(app):
      """Adds any previously created extension objects into the app, and does any further setup they need."""
      enhanced_logging.init_app(app)
-     security_headers.init_app(app)
      # ...
-     content_security_policy.init_app(app)
      # ...
      health.init_app(app)
      health.add_dependencies(DEPENDENCIES)
+     headers.init_app(app, UIDefaultHeaders)
      # ...

You can then remove the content_security_policy and security_headers folders from the custom_extensions folder.

If you have customised these, see below on configuring the new extension.

Default values

Header UI Default API Default
X-Frame-Options DENY
Strict-Transport-Security max-age=31536000 max-age=31536000
X-Content-Type-Options nosniff
Report-To (see below)
Content-Security-Policy (see below) (see below)
X-Content-Security-Policy Same as Content-Security-Policy Same as Content-Security-Policy
X-XSS-Protection 1; mode=block
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy (see below)
Cross-Origin-Embedded-Policy require-corp
Cross-Origin-Opener-Policy same-origin
Cross-Origin-Reosurce-Policy same-origin
X-Permitted-Cross-Domain-Policies none

Default UI CSP Headers

Content-Security-Policy: default-src 'self';script-src 'self' https://*.googletagmanager.com 'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU=' 'sha256-G29/qSW/JHHANtFhlrZVDZW1HOkCDRc78ggbqwwIJ2g=' 'sha256-s7w4Nk/Xk6wc1nlA5PiGroLjvaV+XU1ddIlx89jmBjc=';connect-src 'self' https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com;img-src 'self' https://*.google-analytics.com https://*.googletagmanager.com;font-src 'self' data:;style-src 'self';object-src 'none';block-all-mixed-content;report-uri /content-security-policy-report/;report-to default;

Report-To: {"group":"default","max_age":10886400,"endpoints":[{"url": "<schema>://<host>/content-security-policy-report/"}]}

Default API CSP Headers

Content-Security-Policy: default-src 'none'; frame-ancestors 'none'

Default UI Permissions Policy

Permissions-Policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), speaker-selection=(), conversion-measurement=(), focus-without-user-activation=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), sync-script=(), trust-token-redemption=(), window-management=(), vertical-scroll=()

Overriding defaults

Provide entries in your application configuration (e.g. config.py):

  • X_FRAME_OPTIONS
  • STRICT_TRANSPORT_SECURITY
  • X_CONTENT_TYPE_OPTIONS
  • REPORT_TO
  • CONTENT_SECURITY_POLICY
  • X_XSS_PROTECTION
  • REFERRER_POLICY
  • PERMISSIONS_POLICY
  • CROSS_ORIGIN_EMBEDDER_POLICY
  • CROSS_ORIGIN_OPENER_POLICY
  • CROSS_ORIGIN_RESOURCE_POLICY
  • X_PERMITTED_CROSS_DOMAIN_POLICIES

Whatever you set to the variable will be applied to the corresponding header

CSP Customisation

To customise parts of the Content Security Policy

  • SECURITY_CSP_SCRIPT_HASHES - overrides the default script hashes. Space delimited. Default is
  • SECURITY_CSP_SCRIPT_SOURCES - overrides the default script-src. Default is "https://*.googletagmanager.com"
  • SECURITY_CSP_STYLE_SOURCES - overrides the style-src. Default is "'self'".
  • REPORT_TO_URI - overrides the default URI in the REPORT_TO header.

If overriding SCRIPT_HASHES/SOURCES and want to keep defaults, you can get the default values from DEFAULT_SCRIPT_SOURCES, DEFAULT_SCRIPT_HASHES or DEFAULT_STYLE_SOURCE

Some placeholders may be included in the CSP:

  • {script_src} - replaced with SECURITY_CSP_SCRIPT_SOURCES
  • {script_hashes} - replaced with SECURITY_CSP_SCRIPT_HASHES
  • {style_src} - replaced with SECURITY_CSP_STYLE_SOURCES
  • {report_uri} - replaced with the relative URL of the CSP reporting endpoint

And in the Report-To header:

  • {full_report_uri} - replaced with the full URL of the CSP reporting endpoint

CSP Violation Report Logging

To change how the CSP violation report endpoint logs reports, provide a config entry for CONTENT_SECURITY_POLICY_REPORT_LEVEL.

Valid values are ERROR, WARNING, INFO, and DEBUG, corresponding to to the log level that will be used to log the report. A value of NONE may be provided to stop logging altogether. Be sure you really want to do this.

The default logging level is ERROR if no level is specified.

Per-endpoint overrides

Use the headers object as a decorator to override headers:

@test_blueprint.route("", methods=["GET"])
@headers(X_CONTENT_TYPE_OPTIONS=None, X_XSS_PROTECTION="1")
def get_test():
    return make_response("Test", 200)

Note that this will cause your app to fail (to even start) if you specify headers the extension isn't expecting.

Note this extension won't override headers that you've set in a response. For example, in this case:

@test_blueprint.route("/example")
def example():
    return Response("", 200, headers={'X-Content-Type-Options': 'Setting some nonsense here'})

...the X-Content-Type-Options header will be set to Setting some nonsense here, regardless of extension configuration. Setting a header to None this way will not remove the header, but will set it to the string literal None. Removing headers requires the decorator approach.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

landregistry-security-headers-1.0.5.tar.gz (10.4 kB view hashes)

Uploaded Source

Built Distribution

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page