Support nonce-based Content Security Policy #18499
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR implements gh-10826.
Introduction
When strict Content Security Policy is used, web browsers block inline
<script>or<style>blocks in HTML to mitigate XSS attacks injecting malicious inline blocks. To allow intended inline blocks, web developers can generate a hard-to-guess nonce and specify it in both the CSP and allowed inline blocks.Currently, Spring Security only supports specifying static content security policy directives. This PR introduces support for dynamically generating a secure random nonce for CSP.
Implementation
A nonce is written to the CSP header in 2 steps:
NonceGeneratingFilter/NonceGeneratingWebFiltergenerates a nonce and set it as a request attribute named_csp_nonce;ContentSecurityPolicyHeaderWriter/ContentSecurityPolicyServerHttpHeadersWriterreads the_csp_nonceattribute and write it to the CSP header, replacing the{nonce}placeholder in the configuredpolicyDirectives.Note:
_csp_nonceis chosen as the default attribute name because it has a similar format with the existing_csrfattribute. The attribute name is configurable.Configuration
This PR also adds configurers for set up nonce-based CSP with Java/Kotlin lambda DSL, including the ability to specify a request matcher to determine whether a request requires CSP protection.
The ability to enable CSP conditionally is useful especially when the CSP directives contain a nonce, because the HTTP header value becomes dynamic and may change the cacheability of static asserts protected by Spring Security.
The conditional enabling of CSP protection is implemented in
spring-security-configby wrapping theContentSecurityPolicyHeaderWriter/ContentSecurityPolicyServerHttpHeadersWriterwith the existingDelegatingRequestMatcherHeaderWriter/ServerWebExchangeDelegatingServerHttpHeadersWriter. The_csp_nonceattribute is generated unconditionally if nonce-based CSP is configured.Breaking changes in corner case
In commit 8320c76 I changed the return type of 2 public configuration APIs:
ContentSecurityPolicySpec#reportOnly(boolean)ContentSecurityPolicySpec#policyDirectives(String)The return type is changed from
HeaderSpectoContentSecurityPolicySpecto allow method chaining.I believe this API change was missed during the migration to lambda DSL and think it's small enough to be updated when releasing v7.1, but if 100% API stability is required, we could simply revert that commit, or introduce new APIs and deprecate the old ones.