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-headersto your requirements. - Remove imports and references to
security_headersandcontent_security_policyinbuilt 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_OPTIONSSTRICT_TRANSPORT_SECURITYX_CONTENT_TYPE_OPTIONSREPORT_TOCONTENT_SECURITY_POLICYX_XSS_PROTECTIONREFERRER_POLICYPERMISSIONS_POLICYCROSS_ORIGIN_EMBEDDER_POLICYCROSS_ORIGIN_OPENER_POLICYCROSS_ORIGIN_RESOURCE_POLICYX_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 isSECURITY_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 withSECURITY_CSP_SCRIPT_SOURCES{script_hashes}- replaced withSECURITY_CSP_SCRIPT_HASHES{style_src}- replaced withSECURITY_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.
Metadata
Release files for landregistry-security-headers 0.9.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| landregistry_security_headers-0.9.9.tar.gz | 10.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| landregistry_security_headers-0.9.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.9 kB
Release files / landregistry_security_headers-0.9.9.tar.gz
| Download URL | landregistry_security_headers-0.9.9.tar.gz |
|---|---|
| Size | 10.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0affe7f7997856b679674bec8f8544ed711bd0bb6db77c472b607cb8168ff8fc
|
|
BLAKE2b-256 checksum How to use checksums |
8cfe4ff77ad17602afd0d06d2946945eee5b57e363fb7c980f4fe205f010b3a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.10.12
|
Release files / landregistry_security_headers-0.9.9-py3-none-any.whl
| Download URL | landregistry_security_headers-0.9.9-py3-none-any.whl |
|---|---|
| Size | 10.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
288a8396cbda70b40799cc117f790308c8a11b75df56b39089dd9c2af1676fe7
|
|
BLAKE2b-256 checksum How to use checksums |
0aca8412cc4ad52d3c5981a31dfe51dd09cace410444010ef8d532e205ac0c0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.10.12
|