mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-13 10:30:16 +00:00
middleware: Implement middleware for common headers such as CSP
- This allows overriding these headers in individual pages easily instead of relaxing global policy. - Drop the obsolete CSP directive "block-all-mixed-content" and avoid a console warning in Firefox. Tests: - Load a page and notice in the browser developer tools that the three headers referrer-policy, content-security-policy, and x-content-type-options are set as before. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
3eef1d9324
commit
2467d6a033
@ -47,48 +47,6 @@
|
|||||||
RedirectMatch "^/$" "/plinth"
|
RedirectMatch "^/$" "/plinth"
|
||||||
</IfFile>
|
</IfFile>
|
||||||
|
|
||||||
##
|
|
||||||
## Disable sending Referer (sic) header from FreedomBox web interface to
|
|
||||||
## external websites. This improves privacy by not disclosing FreedomBox
|
|
||||||
## domains/URLs to external domains. Apps such as blogs which want to popularize
|
|
||||||
## themselves with referrer header may still do so.
|
|
||||||
##
|
|
||||||
## A strict Content Security Policy.
|
|
||||||
## - @fonts are allowed only from FreedomBox itself.
|
|
||||||
## - <frame>/<iframe> sources are disabled.
|
|
||||||
## - <img> sources are allowed only from FreedomBox itself.
|
|
||||||
## - Manifest file is not allowed as there is none yet.
|
|
||||||
## - <audio>, <video>, <track> tags are not allowed yet.
|
|
||||||
## - <object>, <embed>, <applet> tags are not allowed yet.
|
|
||||||
## - Allow JS from FreedomBox itself (no inline and attribute scripts).
|
|
||||||
## - Allow inline CSS and CSS files from Freedombox itself.
|
|
||||||
## - Web worker sources are allowed only from FreedomBox itself (for JSXC).
|
|
||||||
## - All other fetch sources including Ajax are not allowed from FreedomBox
|
|
||||||
## itself.
|
|
||||||
## - <base> tag is not allowed.
|
|
||||||
## - No plugins types are alllowed since object-src is 'none'.
|
|
||||||
## - Form action should be to FreedomBox itself.
|
|
||||||
## - This interface may be not embedded in <frame>, <iframe>, etc. tags.
|
|
||||||
## - When serving HTTPS, don't allow HTTP assets.
|
|
||||||
##
|
|
||||||
## Enable strict sandboxing enabled with some exceptions:
|
|
||||||
## - Allow running Javascript.
|
|
||||||
## - Allow popups as sometimes we use <a target=_blank>
|
|
||||||
## - Allow popups to have different sandbox requirements as we launch apps' web
|
|
||||||
## clients.
|
|
||||||
## - Allow forms to support configuration forms.
|
|
||||||
## - Allow policies to treat same origin differently from other origins
|
|
||||||
## - Allow downloads such as backup tarballs.
|
|
||||||
##
|
|
||||||
## Disable browser guessing of MIME types. FreedoBox already sets good content
|
|
||||||
## types for all the common file types.
|
|
||||||
##
|
|
||||||
<LocationMatch "^/(plinth|freedombox)">
|
|
||||||
Header set Referrer-Policy 'same-origin'
|
|
||||||
Header set Content-Security-Policy "font-src 'self'; frame-src 'none'; img-src 'self' data:; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'self'; style-src 'self'; worker-src 'self'; default-src 'self'; base-uri 'none'; sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-same-origin allow-downloads; form-action 'self'; frame-ancestors 'none'; block-all-mixed-content;"
|
|
||||||
Header set X-Content-Type-Options 'nosniff'
|
|
||||||
</LocationMatch>
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## On all sites, provide FreedomBox on a default path: /plinth
|
## On all sites, provide FreedomBox on a default path: /plinth
|
||||||
##
|
##
|
||||||
|
|||||||
@ -188,3 +188,93 @@ class CommonErrorMiddleware(MiddlewareMixin):
|
|||||||
breadcrumbs = views.get_breadcrumbs(request)
|
breadcrumbs = views.get_breadcrumbs(request)
|
||||||
parent_index = 1 if len(breadcrumbs) > 1 else 0
|
parent_index = 1 if len(breadcrumbs) > 1 else 0
|
||||||
return list(breadcrumbs.keys())[parent_index]
|
return list(breadcrumbs.keys())[parent_index]
|
||||||
|
|
||||||
|
|
||||||
|
class CSPDict(dict):
|
||||||
|
"""A dictionary to store Content Security Policy.
|
||||||
|
|
||||||
|
And return a full value of the HTTP header.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_header_value(self) -> str:
|
||||||
|
"""Return the string header value for the policy stored."""
|
||||||
|
return ' '.join([f'{key} {value};' for key, value in self.items()])
|
||||||
|
|
||||||
|
|
||||||
|
CONTENT_SECURITY_POLICY = CSPDict({
|
||||||
|
# @fonts are allowed only from FreedomBox itself.
|
||||||
|
'font-src': "'self'",
|
||||||
|
# <frame>/<iframe> sources are disabled.
|
||||||
|
'frame-src': "'none'",
|
||||||
|
# <img> sources are allowed only from FreedomBox itself. Allow
|
||||||
|
# data: URLs for SVGs in CSS.
|
||||||
|
'img-src': "'self' data:",
|
||||||
|
# Manifest file is not allowed as there is none yet.
|
||||||
|
'manifest-src': "'none'",
|
||||||
|
# <audio>, <video>, <track> tags are not allowed yet.
|
||||||
|
'media-src': "'none'",
|
||||||
|
# <object>, <embed>, <applet> tags are not allowed yet. No plugins
|
||||||
|
# types are alllowed since object-src is 'none'.
|
||||||
|
'object-src': "'none'",
|
||||||
|
# Allow JS from FreedomBox itself (no inline and attribute
|
||||||
|
# scripts).
|
||||||
|
'script-src': "'self'",
|
||||||
|
# Allow inline CSS and CSS files from Freedombox itself.
|
||||||
|
'style-src': "'self'",
|
||||||
|
# Web worker sources are allowed only from FreedomBox itself (for
|
||||||
|
# JSXC).
|
||||||
|
'worker-src': "'self'",
|
||||||
|
# All other fetch sources including Ajax are not allowed from
|
||||||
|
# FreedomBox itself.
|
||||||
|
'default-src': "'self'",
|
||||||
|
# <base> tag is not allowed.
|
||||||
|
'base-uri': "'none'",
|
||||||
|
# Enable strict sandboxing enabled with some exceptions:
|
||||||
|
# - Allow running Javascript.
|
||||||
|
# - Allow popups as sometimes we use <a target=_blank>
|
||||||
|
# - Allow popups to have different sandbox requirements as we
|
||||||
|
# launch apps' web clients.
|
||||||
|
# - Allow forms to support configuration forms.
|
||||||
|
# - Allow policies to treat same origin differently from other
|
||||||
|
# - origins
|
||||||
|
# - Allow downloads such as backup tarballs.
|
||||||
|
'sandbox': 'allow-scripts allow-popups '
|
||||||
|
'allow-popups-to-escape-sandbox allow-forms '
|
||||||
|
'allow-same-origin allow-downloads',
|
||||||
|
# Form action should be to FreedomBox itself.
|
||||||
|
'form-action': "'self'",
|
||||||
|
# This interface may be not embedded in <frame>, <iframe>, etc.
|
||||||
|
# tags.
|
||||||
|
'frame-ancestors': "'none'",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class CommonHeadersMiddleware:
|
||||||
|
|
||||||
|
def __init__(self, get_response):
|
||||||
|
"""Initialize the middleware object."""
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
|
"""Add common security middleware."""
|
||||||
|
# Disable sending Referer (sic) header from FreedomBox web interface to
|
||||||
|
# external websites. This improves privacy by not disclosing FreedomBox
|
||||||
|
# domains/URLs to external domains. Apps such as blogs which want to
|
||||||
|
# popularize themselves with referrer header may still do so.
|
||||||
|
response = self.get_response(request)
|
||||||
|
if not response.get('Referrer-Policy'):
|
||||||
|
response['Referrer-Policy'] = 'same-origin'
|
||||||
|
|
||||||
|
# Disable browser guessing of MIME types. FreedoBox already sets good
|
||||||
|
# content types for all the common file types.
|
||||||
|
if not response.get('X-Content-Type-Options'):
|
||||||
|
response['X-Content-Type-Options'] = 'nosniff'
|
||||||
|
|
||||||
|
csp = ' '.join([
|
||||||
|
f'{key} {value};'
|
||||||
|
for key, value in CONTENT_SECURITY_POLICY.items()
|
||||||
|
])
|
||||||
|
if not response.get('Content-Security-Policy'):
|
||||||
|
response['Content-Security-Policy'] = csp
|
||||||
|
|
||||||
|
return response
|
||||||
|
|||||||
@ -149,6 +149,7 @@ LOGIN_REDIRECT_URL = 'index'
|
|||||||
MESSAGE_TAGS: dict = {}
|
MESSAGE_TAGS: dict = {}
|
||||||
|
|
||||||
MIDDLEWARE = (
|
MIDDLEWARE = (
|
||||||
|
'plinth.middleware.CommonHeadersMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user