Feature: #100887 - Prefer CSP hash values over nonce values 

See forge#100887

Description 

Content-Security-Policy nonce values are random tokens in each request that prevent HTTP response caching. By collecting hash values of assets at render time instead, responses can be cached, for example by using lochmueller/staticfilecache or reverse proxies, while still enforcing a strict CSP.

Hash-based CSP is an explicit opt-in configured for a site via csp.yaml. Nonce values remain the default when no behavior is configured.

New DirectiveHashCollection service 

The new \TYPO3\CMS\Core\Security\ContentSecurityPolicy\DirectiveHashCollection service is a per-request registry that collects CSP hash values for inline and static assets during page rendering.

Both inline content and static file resources are supported:

  • Inline assets: the SHA-256 hash is computed over the content that appears inside the <script> or <style> element.
  • Static assets: if an integrity attribute is already present, its value is reused; otherwise, the file content is hashed on demand.
  • Style attributes: the new f:asset.styleAttr ViewHelper hashes inline style values and covers the style-src-attr directive.

The collected hashes survive the frontend page cache round-trip via \TYPO3\CMS\Frontend\Cache\MetaDataState .

Updated Behavior class 

\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Configuration\Behavior now carries a second nullable boolean property, $useHash:

  • true explicitly enables hash collection and CSP hash sources.
  • null means off, which is the default. Hashes are not collected or applied.
  • false explicitly disables hash collection and CSP hash sources.

Configuring behavior via csp.yaml 

Both $useNonce and $useHash can be set in a site's config/sites/<site>/csp.yaml under the top-level behavior: key:

behavior:
  useNonce: false
  useHash: true

enforce:
  inheritDefault: true
  includeResolutions: true
Copied!

Setting useHash: true enables hash-based CSP for that site. Setting useNonce: false removes nonce sources from the compiled policy, which is required for responses to be cacheable by reverse proxies.

Updated Policy::prepare() and Policy::compile() 

Both methods now accept a \TYPO3\CMS\Core\Security\ContentSecurityPolicy\Middleware\PolicyBag instead of separate ConsumableNonce, Behavior, and HashCollection arguments. The PolicyBag is forwarded directly from the CSP middleware, making hash collection visible to PSR-14 event listeners via PolicyPreparedEvent::$policyBag->directiveHashCollection.

The behavior resolution, applying collected hashes and suppressing nonce sources, now happens inside Policy::prepare().

New f:asset.styleAttr ViewHelper 

A new ViewHelper registers inline style values using the style-src-attr CSP directive:

<div style="{f:asset.styleAttr(value: 'color: green', csp: true)}"></div>
Copied!

The csp argument defaults to true and controls whether the hash is collected.

Updated f:asset.script and f:asset.css ViewHelpers 

The useNonce argument has been renamed to csp (deprecated, see Deprecation: #100887 - Deprecation of useNonce argument in f:asset:css and f:asset:script view helpers). The new default is true for external files, that is, static resources, and false for inline content.

<!-- static file: csp=1 by default, hash collected from file content -->
<f:asset.script
    identifier="my-script"
    src="EXT:my_ext/Resources/Public/JavaScript/foo.js"
/>

<!-- with integrity attribute: hash reused directly, no file read -->
<f:asset.script
    identifier="my-script"
    src="EXT:my_ext/Resources/Public/JavaScript/foo.js"
    integrity="sha256-abc123=="
/>

<!-- inline script: opt in explicitly -->
<f:asset.script identifier="my-inline" csp="1">
    document.querySelector('.foo').classList.add('active');
</f:asset.script>
Copied!

Migration 

The useNonce ViewHelper argument and 'useNonce' asset option key are deprecated and replaced by csp and 'csp'. See Deprecation: #100887 - Deprecation of useNonce argument in f:asset:css and f:asset:script view helpers.

The signature of Policy::prepare() and Policy::compile() has changed to accept a PolicyBag. Code calling these methods directly, as they are marked @internal, must be updated.

Impact 

Sites that configure behavior.useHash: true, and optionally behavior.useNonce: false, in their csp.yaml can use hash-based CSP sources. This allows HTTP responses to be cached by reverse proxies and static file cache extensions without sacrificing Content-Security-Policy enforcement. Sites without this configuration continue to use nonce-based CSP.