diff --git a/admin-manual/customization/config-files.rst b/admin-manual/customization/config-files.rst index 87f29fa1..2da04fd7 100644 --- a/admin-manual/customization/config-files.rst +++ b/admin-manual/customization/config-files.rst @@ -178,6 +178,12 @@ such as: are co-tenanted on the same server. * ``treeview_items_per-page_max``: Increase the maximum allowed value for the full-width :term:`treeview` paging limit - see: :ref:`fwt-items-per-page` +* ``response_header``: The CSP `repsonse_header` setting is used to set the CSP + header type and can have one of two values: `Content-Security-Policy` or + `Content-Security-Policy-Report-Only`. See :ref:`csp-configuration` for + additional details. +* ``directives``: The CSP `directives` setting contains the CSP policy that will + be sent in the CSP header. See :ref:`csp-configuration` for additional details. .. image:: images/app-yml-settings.* :align: center diff --git a/admin-manual/security/csp-headers.rst b/admin-manual/security/csp-headers.rst new file mode 100644 index 00000000..96ea2963 --- /dev/null +++ b/admin-manual/security/csp-headers.rst @@ -0,0 +1,275 @@ +.. _security-csp-headers: + +=============================== +Content Security Policy Headers +=============================== + +Content Security Policy (`CSP`_) headers are a critical component of web security, +serving as a robust defense against a wide range of online threats. These +headers, which are implemented on web servers and embedded within web pages, +define a set of directives that instruct a browser on how to handle and restrict +the execution of various web resources, such as scripts, stylesheets, and +images. + +The primary function of CSP headers is to mitigate the risks associated with +cross-site scripting (`XSS`_) attacks, data injection attacks, and other malicious +activities that exploit the trust model of web applications. By specifying which +sources of content are permitted, CSP headers help prevent unauthorized code +execution and reduce the attack surface, enhancing the overall security posture +of web applications. + +Starting in AtoM 2.8, AtoM has built in support for CSP headers when Bootstrap 5 +based themes are in use. When installing AtoM 2.8 from scratch, there's +a pre-configured CSP directive setting in place and CSP headers will be in use by +default. These default settings serve as a foundation compatible with the upgraded +Bootstrap 5 based Dominion theme and can be used as a base for custom themes based +on Dominion. + +.. _csp-overview: + +Content Security Policy headers +------------------------------- + +In a high-level example of web security using Content Security Policy (CSP), +let's consider a scenario. When a user's web browser sends a request to a server +for a particular web page, the server responds by generating the page response +and including a CSP header. This CSP header specifies trusted sources from which +scripts, stylesheets, images, and other assets can be loaded and executed. +Additionally, the server generates a unique nonce (number used once) and adds it +to all inline scripts and other assets within the response. + +Once the response is sent to the user's browser, the browser acts as a security +enforcer. It checks each requested resource and script against the CSP +directive. If any resource or script does not match the trusted sources +specified in the CSP header or lacks the correct nonce, the browser rejects those +elements, preventing them from loading or executing. This strict validation +process ensures that only content from trusted sources, as defined by the CSP, +is allowed to run on the webpage. In doing so, CSP effectively protects against +cross-site scripting (`XSS`_) attacks and other security threats, making the +user's browsing experience safer and more secure. + +.. mermaid:: + + sequenceDiagram + participant Browser + participant Server + + Browser ->> Server: HTTP Request + note over Server: Generate unique nonce and
store in session variable + note over Server: Build CSP header directive including nonce to use in reponse + + note over Server: Tag each inline script with nonce + Server ->> Browser: HTTP Response + note over Browser: Verify reponse sources
against values in CSP directive
rejecting any that do not match + + +.. _csp-configuration: + +AtoM's CSP configuration +------------------------ + +This is the default configuration you'll find in AtoM's :ref:`config-app-yml` file: + +.. code-block:: yaml + + # Content Security Policy (CSP) header configuration. CSP settings apply + # only when a B5 theme is active, else these settings are bypassed. + csp: + response_header: Content-Security-Policy + directives: "default-src 'self'; font-src 'self'; img-src 'self' https://www.gravatar.com/avatar/ blob:; script-src 'self' 'nonce'; style-src 'self' 'nonce'; worker-src 'self' blob:; frame-ancestors 'self';" + +The CSP ``repsonse_header`` setting is used to set the CSP header type and can have one of +two values: + +- **Content-Security-Policy**: + This setting will enforce the defined policy. When set, the browser will block any + resources (scripts, images, stylesheets, etc.) that violate the policy directives. + +- **Content-Security-Policy-Report-Only**: + This header works similarly to the ``Content-Security-Policy`` but does not block any + resources allowing developers to test and monitor potential violations without + affecting the functionality of the web page. This is useful for testing a new policy or + changes to an existing policy without risking breakage. Violations will be reported to + the browser's console. + +The CSP ``directives`` setting contains the CSP policy that will be sent in the CSP header. +The value for the ``directives`` setting above is the default when the Dominion theme is +in use. Multiple directives get delineated with a semicolon (``;``). + +.. IMPORTANT:: + The value ``nonce`` in the above example is a placeholder and will be replaced + with a generated unique value when AtoM generates the page response. + +The specific directives defined in the defaults above are as follows: + +- default-src: if resources aren't mentioned in other sections, this policy is applied. +- font-src: stipulates which fonts can be loaded. +- img-src: stipulates which images can be loaded. +- script-src: stipulates which scripts can be loaded. +- style-src: stipulates which styles or CSS can be loaded. +- frame-ancestors 'self': determines which domains can embed the page as a frame. + +Specifying ``self`` ensures that only trusted resources from the *same origin* are loaded +and executed. + +Updating these settings will require restarting :ref:`PHP-FPM `. + +.. IMPORTANT:: + + CSP headers will only be applied to a response if a Bootstrap 5 based theme is in use. See: + * :ref:`customization-theming` + * :ref:`themes` + +CSP headers can be deactivated by deleting the CSP section from the :ref:`config-app-yml` +file, saving the file, and restarting :ref:`PHP-FPM `. + +.. _csp-custom-themes: + +Implementing a Content Security Policy For Your Custom Theme +------------------------------------------------------------ + +1. Begin with a basic CSP directive. + + If your custom theme is derived from AtoM's Dominion Bootstrap 5 theme, begin + with the baseline CSP directive from AtoM's :ref:`config-app-yml`: + + .. code-block:: none + + Content-Security-Policy-Report-Only: default-src 'self'; font-src 'self'; img-src 'self' https://www.gravatar.com/avatar/ blob:; script-src 'self' 'nonce'; style-src 'self' 'nonce'; worker-src 'self' blob:; frame-ancestors 'self'; + + In app.yml this would look like: + + .. code-block:: yaml + + # Content Security Policy (CSP) header configuration. CSP settings apply + # only when a B5 theme is active, else these settings are bypassed. + csp: + response_header: Content-Security-Policy-Report-Only + directives: "default-src 'self'; font-src 'self'; img-src 'self' https://www.gravatar.com/avatar/ blob:; script-src 'self' 'nonce'; style-src 'self' 'nonce'; worker-src 'self' blob:; frame-ancestors 'self';" + + For those who have crafted a custom theme, but haven't used AtoM's default Bootstrap 5 + Dominion theme as a foundation, it's recommended to start with a more restrictive + `content-security-policy` header: + + .. code-block:: none + + Content-Security-Policy-Report-Only: default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; + + In app.yml this would look like: + + .. code-block:: yaml + + # Content Security Policy (CSP) header configuration. CSP settings apply + # only when a B5 theme is active, else these settings are bypassed. + csp: + response_header: Content-Security-Policy-Report-Only + directives: "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-ancestors 'self';" + + These examples reference the ``Content-Security-Policy-Report-Only`` header - + this header will log violations in Chrome's Developer Tools but will not + prevent a script from loading and running. This is helpful when developing a + policy so that the pages and all scripts still load properly - while ensuring + all violations will be seen in the console log. When the policy definition is + ready to go live this CSP header type can be changed to ``Content-Security-Policy`` + to activate enforcement. + +2. Monitor in the browser watching for CSP violations. + + The line number can be obtained from the error as shown in Chrome's dev tools console. + +3. Look for and fix any violations by adding nonce to inline script, style, etc. + + Use "view source" to find the implicated line - find and fix the violation in the + underlying code. Most of these are going to be inline assets - scripts, styles, etc. + See: :ref:`cap-allow-inline-sources`. + +4. Activate policy enforcement. + + Once you are convinced you've caught all the violations, activate enforcement + of the CSP policy by changing the header from + ``Content-Security-Policy-Report-Only`` to ``Content-Security-Policy``. + +.. _csp-allow-inline-sources: + +Safely Allowing Inline Sources +------------------------------ + +If your application has inline scripts there are 4 choices: + +1. Usage of ``unsafe-inline`` should be avoided. + + Allowing ``unsafe-inline`` in a CSP directive permits inline scripts or styles from + any source to run. While it offers design flexibility, it's discouraged due to + heightened risk of XSS attacks. This setting can expose web applications to + malicious script injections, undermining CSP's security benefits and so using + ``unsafe-inline`` should be avoided. + +2. Add the hash of the script to the CSP directive. + + Adding a script's hash to the CSP directive allows for specific inline scripts + to execute based on their hashed content. While this method ensures only the + approved script runs, it's fragile because any change to the script's content + requires recalculating and updating its hash in the CSP. This can be cumbersome + and error-prone, especially with frequent script modifications. + + In addition, if there are a large number of violations, there could mean a lot of + hashes to add, creating a very messy CSP directive. + +3. For a given request generate a random nonce value to be returned in the CSP + header directive and on each inline script, style etc tag. + + Each inline script or style has to be flagged as 'ok' with a nonce (a random + token) value that is uniquely generated for a specific request/response pair. + This nonce must be included in the Header directive, and in each inline script + (or style, font, img source) tag. If your application has lots of inline + scripts, styles and whatnot this could be a lot of work, but it will be + more robust than using script hashes. + + .. code-block:: none + + Content-Security_policy-Report-Only: default-src 'self'; font-src 'self'; img-src 'self' https://www.gravatar.com/avatar/ blob:; script-src 'self' 'nonce-abcd1234567890'; style-src 'self' 'nonce-abcd1234567890'; worker-src 'self' blob:; frame-ancestors 'self'; + +4. Remove the inline asset! Refactor the code to move the inline asset to the + script and style bundle. If it's an inline style can it be replaced with a + Bootstrap 5 equivalent? + +Work completed to make the Dominion theme compatible with CSP headers can be viewed +in this `AtoM CSP commit`_. This commit provides examples of how to refer to the nonce +value generated by AtoM from your theme templates, and examples of refactoring code to +remove inline styles in favour of Bootstrap 5 equivalents. + +.. _csp-allow-external-sources: + +Allowing External Sources +------------------------- + +If for example the application makes use of Gravatar assets, we could allow them by +adding: + +.. code-block:: none + + Content-Security-Policy-Report-Only: default-src 'self'; font-src 'self'; img-src 'self' https://www.gravatar.com/avatar/; script-src 'self'; style-src 'self'; frame-ancestors 'self'; + +Note it is good to be as specific as possible without creating a maintainance +headache when specifying the domain. E.g. if all assets are loaded from the +``avatar`` endpoint, then it is better to be more specific than allow scripts +to be run from the entire ``https://www.gravatar.com`` domain. + +If your theme makes use of Google Analytics, Tag Manager, or the Maps API, then +you may need to whitelist additional sources. We recommend consulting Google's +documentation for this: + +* https://developers.google.com/tag-manager/web/csp +* https://developers.google.com/web/fundamentals/security/csp/ +* https://content-security-policy.com/examples/google-maps/ + +.. SEEALSO:: + + Additional AtoM documentation links related to Google service integrations: + + * :ref:`maintenance-web-analytics` + * :ref:`maps-api-key` + +.. _`AtoM CSP commit`: https://github.com/artefactual/atom/commit/d796a1f7252aa6ce6c4ef611fac91939584df00b +.. _`CSP`: https://en.wikipedia.org/wiki/Content_Security_Policy +.. _`XSS`: https://owasp.org/www-community/attacks/xss/ \ No newline at end of file diff --git a/admin-manual/security/index.rst b/admin-manual/security/index.rst index de2747df..7646f488 100644 --- a/admin-manual/security/index.rst +++ b/admin-manual/security/index.rst @@ -8,5 +8,6 @@ Security :maxdepth: 1 application + csp-headers firewall backups diff --git a/index.rst b/index.rst index 9ccb8215..a4625efb 100644 --- a/index.rst +++ b/index.rst @@ -249,6 +249,7 @@ Security -------- * :ref:`security-application` +* :ref:`security-csp-headers` * :ref:`security-firewall` * :ref:`security-backups`