Name | landregistry-security-headers JSON |
Version |
0.9.9
JSON |
| download |
home_page | None |
Summary | Standardised exception security related HTTP headers for HMLR Flask applications |
upload_time | 2024-10-31 13:54:47 |
maintainer | None |
docs_url | None |
author | Ian Harvey |
requires_python | >=3.9 |
license | MIT |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# 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:
```python
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.
```diff
# ...
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 <something>
- `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:
```python
@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:
```python
@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.
Raw data
{
"_id": null,
"home_page": null,
"name": "landregistry-security-headers",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Ian Harvey",
"author_email": "ian.harvey@landregistry.gov.uk",
"download_url": "https://files.pythonhosted.org/packages/8c/fe/4ff77ad17602afd0d06d2946945eee5b57e363fb7c980f4fe205f010b3a4/landregistry_security_headers-0.9.9.tar.gz",
"platform": null,
"description": "# Security Headers for Flask Web Applications\n\nConvienience Flask extension for setting security headers. See below for the full list.\n\n**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.\n\nThis package depends on:\n\n- Flask\n\n## Usage\n\nInstantiate it like a normal flask extension:\n\n```python\nfrom landregistry.security_headers import SecurityHeaders, UIDefaultHeaders\nfrom <somewhere> import app\n\n# ...\n\nheaders = SecurityHeaders()\nheaders.init_app(app, UIDefaultHeaders)\n```\n\nThree default configurations are provided:\n\n- `UIDefaultHeaders` - a set of headers suited for a web front-end.\n- `APIDefaultHeaders` - a set of headers suited for a REST API.\n- `EmptyDefaultHeaders` - no defaults.\n\n### Updating an existing UI\n\nIf 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:\n\n- Add `landregistry-security-headers` to your requirements.\n- Remove imports and references to `security_headers` and `content_security_policy` inbuilt packages\n- Add imports and initialisation of the new extension.\n\n```diff\n # ...\n from landregistry.healthchecks import HealthChecks\n+ from landregistry.security_headers import SecurityHeaders, UIDefaultHeaders\n\n from server import config\n # ...\n- from server.custom_extensions.content_security_policy.main import ContentSecurityPolicy\n # ...\n- from server.custom_extensions.security_headers.main import SecurityHeaders\n from server.exceptions import application_error_renderer, http_error_renderer, unhandled_error_renderer\n\n # Create empty extension objects here\n # ...\n- security_headers = SecurityHeaders()\n # ...\n- content_security_policy = ContentSecurityPolicy()\n # ...\n health = HealthChecks()\n+ headers = SecurityHeaders()\n\n def register_extensions(app):\n \"\"\"Adds any previously created extension objects into the app, and does any further setup they need.\"\"\"\n enhanced_logging.init_app(app)\n- security_headers.init_app(app)\n # ...\n- content_security_policy.init_app(app)\n # ...\n health.init_app(app)\n health.add_dependencies(DEPENDENCIES)\n+ headers.init_app(app, UIDefaultHeaders)\n # ...\n```\n\nYou can then remove the `content_security_policy` and `security_headers` folders from the `custom_extensions` folder.\n\nIf you have customised these, see below on configuring the new extension.\n\n### Default values\n\n| Header | UI Default | API Default |\n| --------------------------------- | ------------------------------- | ---------------- |\n| X-Frame-Options | DENY | |\n| Strict-Transport-Security | max-age=31536000 | max-age=31536000 |\n| X-Content-Type-Options | nosniff | |\n| Report-To | (see below) | |\n| Content-Security-Policy | (see below) | (see below) |\n| X-Content-Security-Policy | Same as Content-Security-Policy | Same as Content-Security-Policy |\n| X-XSS-Protection | 1; mode=block | |\n| Referrer-Policy | strict-origin-when-cross-origin | |\n| Permissions-Policy | (see below) | |\n| Cross-Origin-Embedded-Policy | require-corp | |\n| Cross-Origin-Opener-Policy | same-origin | |\n| Cross-Origin-Reosurce-Policy | same-origin | |\n| X-Permitted-Cross-Domain-Policies | none | |\n\n\n**Default UI CSP Headers**\n\n```\nContent-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;\n\nReport-To: {\"group\":\"default\",\"max_age\":10886400,\"endpoints\":[{\"url\": \"<schema>://<host>/content-security-policy-report/\"}]}\n```\n\n**Default API CSP Headers**\n\n```\nContent-Security-Policy: default-src 'none'; frame-ancestors 'none'\n```\n\n**Default UI Permissions Policy**\n\n```\nPermissions-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=()\n```\n\n### Overriding defaults\n\nProvide entries in your application configuration (e.g. `config.py`):\n\n- `X_FRAME_OPTIONS`\n- `STRICT_TRANSPORT_SECURITY`\n- `X_CONTENT_TYPE_OPTIONS`\n- `REPORT_TO`\n- `CONTENT_SECURITY_POLICY`\n- `X_XSS_PROTECTION`\n- `REFERRER_POLICY`\n- `PERMISSIONS_POLICY`\n- `CROSS_ORIGIN_EMBEDDER_POLICY`\n- `CROSS_ORIGIN_OPENER_POLICY`\n- `CROSS_ORIGIN_RESOURCE_POLICY`\n- `X_PERMITTED_CROSS_DOMAIN_POLICIES`\n\nWhatever you set to the variable will be applied to the corresponding header\n\n### CSP Customisation\n\nTo customise parts of the Content Security Policy\n\n- `SECURITY_CSP_SCRIPT_HASHES` - overrides the default script hashes. Space delimited. Default is <something>\n- `SECURITY_CSP_SCRIPT_SOURCES` - overrides the default script-src. Default is \"https://*.googletagmanager.com\"\n- `SECURITY_CSP_STYLE_SOURCES` - overrides the style-src. Default is \"'self'\".\n- `REPORT_TO_URI` - overrides the default URI in the REPORT_TO header.\n\nIf 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`\n\nSome placeholders may be included in the CSP:\n\n- `{script_src}` - replaced with `SECURITY_CSP_SCRIPT_SOURCES`\n- `{script_hashes}` - replaced with `SECURITY_CSP_SCRIPT_HASHES`\n- `{style_src}` - replaced with `SECURITY_CSP_STYLE_SOURCES`\n- `{report_uri}` - replaced with the relative URL of the CSP reporting endpoint\n\nAnd in the Report-To header:\n\n- `{full_report_uri}` - replaced with the full URL of the CSP reporting endpoint\n\n### CSP Violation Report Logging\n\nTo change how the CSP violation report endpoint logs reports, provide a config entry for `CONTENT_SECURITY_POLICY_REPORT_LEVEL`.\n\nValid 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**.\n\nThe default logging level is `ERROR` if no level is specified.\n\n### Per-endpoint overrides\n\nUse the `headers` object as a decorator to override headers:\n\n```python\n@test_blueprint.route(\"\", methods=[\"GET\"])\n@headers(X_CONTENT_TYPE_OPTIONS=None, X_XSS_PROTECTION=\"1\")\ndef get_test():\n return make_response(\"Test\", 200)\n```\n\nNote that this will cause your app to fail (to even start) if you specify headers the extension isn't expecting.\n\nNote this extension won't override headers that you've set in a response. For example, in this case:\n\n```python\n@test_blueprint.route(\"/example\")\ndef example():\n return Response(\"\", 200, headers={'X-Content-Type-Options': 'Setting some nonsense here'})\n```\n\n...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.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Standardised exception security related HTTP headers for HMLR Flask applications",
"version": "0.9.9",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0aca8412cc4ad52d3c5981a31dfe51dd09cace410444010ef8d532e205ac0c0b",
"md5": "2453454d51ea8c16d4aacc2ef8f26aaf",
"sha256": "288a8396cbda70b40799cc117f790308c8a11b75df56b39089dd9c2af1676fe7"
},
"downloads": -1,
"filename": "landregistry_security_headers-0.9.9-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2453454d51ea8c16d4aacc2ef8f26aaf",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 10531,
"upload_time": "2024-10-31T13:54:44",
"upload_time_iso_8601": "2024-10-31T13:54:44.863271Z",
"url": "https://files.pythonhosted.org/packages/0a/ca/8412cc4ad52d3c5981a31dfe51dd09cace410444010ef8d532e205ac0c0b/landregistry_security_headers-0.9.9-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8cfe4ff77ad17602afd0d06d2946945eee5b57e363fb7c980f4fe205f010b3a4",
"md5": "b046552ca9d0bd9ca3a24f33a6f62294",
"sha256": "0affe7f7997856b679674bec8f8544ed711bd0bb6db77c472b607cb8168ff8fc"
},
"downloads": -1,
"filename": "landregistry_security_headers-0.9.9.tar.gz",
"has_sig": false,
"md5_digest": "b046552ca9d0bd9ca3a24f33a6f62294",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 10408,
"upload_time": "2024-10-31T13:54:47",
"upload_time_iso_8601": "2024-10-31T13:54:47.283598Z",
"url": "https://files.pythonhosted.org/packages/8c/fe/4ff77ad17602afd0d06d2946945eee5b57e363fb7c980f4fe205f010b3a4/landregistry_security_headers-0.9.9.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-31 13:54:47",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "landregistry-security-headers"
}