Remove Unnecessary 'unsafe-hashes' from style-src in CSP
lanzosuarez opened this issue · 1 comments
I've noticed that the library is currently adding 'unsafe-hashes' to the style-src
directive in the Content Security Policy (CSP). As per the CSP standard, 'unsafe-hashes' is intended for use with script-src
to allow specific inline scripts, and its use within style-src
is non-standard and unnecessary. This inclusion could potentially lead to confusion and might not align with best practices for CSP implementation.
Steps to Reproduce
- Use
strictInlineStyles
in the security middleware insidemiddleware.ts
import {
chainMatch,
isPageRequest,
csp,
strictDynamic,
strictInlineStyles,
} from "@next-safe/middleware";
const securityMiddleware = [
...,
strictDynamic(),
strictInlineStyles(),
];
export default chainMatch(isPageRequest)(...securityMiddleware);
- Pass
trustifyStyles: true
in thegetCspInitialProps
call inside document.ts
const initialProps = await getCspInitialProps({
ctx,
trustifyStyles: true,
});
- Observe the generated CSP header.
- Note the inclusion of 'unsafe-hashes' in the
style-src
directive.
Expected Behavior
The style-src directive should not include 'unsafe-hashes', as this is not a standard practice for styling and it does not enhance security for styles.
Actual Behavior
The CSP header generated by the library includes 'unsafe-hashes' in the style-src directive.
Possible Solution
In builder.ts
inside withStyleHashes
, remove the addition of the [unsafe-hashes]
in the style-src
directive
public withStyleHashes(
elemHashes: HashWithAlgorithm[] = [],
attrHashes: HashWithAlgorithm[] = [],
removeUnsafeInline = true
) {
const unsafeHashes = attrHashes.length ? ["unsafe-hashes"] : []; // remove this line
if (elemHashes.length || attrHashes.length) {
this.withDirectives({
"style-src": [...elemHashes, ...attrHashes, ...unsafeHashes], // remove the ...unsafeHashes part
});
}
if (this.hasDirective("style-src-elem") && elemHashes.length) {
this.withDirectives({
"style-src-elem": [...elemHashes],
});
}
if (this.hasDirective("style-src-attr") && attrHashes.length) {
this.withDirectives({
"style-src-attr": [...attrHashes, ...unsafeHashes], // remove the ...unsafeHashes part
});
}
if (removeUnsafeInline) {
this.withoutDirectiveValues({
"style-src": ["unsafe-inline"],
"style-src-elem": ["unsafe-inline"],
"style-src-attr": ["unsafe-inline"],
});
}
return this;
}
Turns out the unsafe-hashes
is needed in Chrome for the hashes to be "Matched"