DEV Community

Jen C.
Jen C.

Posted on

Security - Solving the "Content Security Policy (CSP) Header Not Set": style-src

Resources

Content-Security-Policy: default-src directive

Content-Security-Policy: style-src directive

HTMLElement: style property

Background

Inspect the codebase for all current usages, and based on the findings, either adjust the value of style-src accordingly or update the codebase to a more secure implementation, then update the value of style-src.

Style usage in the project

Inline style property

...

<div
    className={background.className}
    style={{
        backgroundImage: `url(${background.url})`,
    }}
/>

...
Enter fullscreen mode Exit fullscreen mode

Unsafe inline styles

...

return (
    <>
      <Head />
      {isiOS && (
        <NextHead>
          <style>
            {`
              html,
              body {
                height: 100vh;
              }
            `}
          </style>
        </NextHead>
      )}

    ...

    </> 
...

Enter fullscreen mode Exit fullscreen mode

Styles that are applied in JavaScript by setting the style attribute directly or by using cssText

For example:

document.querySelector("div").setAttribute("style", "display:none;");
document.querySelector("div").style.cssText = "display:none;";
Enter fullscreen mode Exit fullscreen mode

NOTE: our project does not have this

Style properties that are set directly on an element’s style property.

const Drawer = ({ open, onClick }) => {
  useEffect(() => {
    document.body.style.position = open ? 'fixed' : 'static';
    document.body.style.width = open ? '100%' : 'auto';
    document.body.style.overflow = open ? 'hidden' : 'auto';
  }, [open]);

...
Enter fullscreen mode Exit fullscreen mode

Step-by-step guide

Set the Content Security Policy (CSP) header to include:

style-src 'self' 'nonce-${nonce}';
Enter fullscreen mode Exit fullscreen mode

Dynamically generate a nonce and set it in the x-nonce response header. For example, in Next.js middleware:

...

export function middleware(request) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
  const cspHeader = `
    default-src 'self';
    style-src 'self' 'nonce-${nonce}';
`;
  // Replace newline characters and spaces
  const contentSecurityPolicyHeaderValue = cspHeader
    .replace(/\s{2,}/g, ' ')
    .trim();

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);
  requestHeaders.set(
    'Content-Security-Policy',
    contentSecurityPolicyHeaderValue
  );

  const response = NextResponse.next({
    request: {
      headers: requestHeaders,
    },
  });
  response.headers.set(
    'Content-Security-Policy',
    contentSecurityPolicyHeaderValue
  );

  return response;
}
Enter fullscreen mode Exit fullscreen mode

In the code that uses unsafe inline styles, retrieve the nonce value from the x-nonce request header and set it as the nonce attribute on the <style> element.

For example, the unsafe inline styles:

...

return (
    <>
      <Head />
      {isiOS && (
        <NextHead>
          <style nonce={nonce}>
            {`
              html,
              body {
                height: 100vh;
              }
            `}
          </style>
        </NextHead>
      )}

    ...

    </> 
...

Enter fullscreen mode Exit fullscreen mode

However, according to 'nonce-'

If a directive contains a nonce and unsafe-inline, then the browser ignores unsafe-inline.

Since our project heavily relies on inline style properties, we need to refactor the code to use class names in order to resolve this error.

However, many of these inline styles depend on JavaScript variables at runtime, making it impractical to convert them to class names. For example:

 <div
      data-testid='detail-meta'
      className='detail-meta'
      style={{
        minHeight: isArtist ? '14vw' : 'auto',
      }}>

      ...

  </div>
Enter fullscreen mode Exit fullscreen mode

Therefore, we set the style-src directive to 'self' 'unsafe-inline' instead of using a nonce to resolve this issue.

Further thoughts

What happens if we remove default-src and do not add any fetch directives?

For example, if we remove default-src along with style-src, style-src-elem, and style-src-attr from the Content-Security-Policy headers.

Removing default-src and using wildcards for other directives fails to resolve the Content Security Policy (CSP) Header Not Set error and the complex style-src issues. In fact, it causes additional problems:

  • CSP: Failure to Define Directive with No Fallback
  • CSP: Wildcard Directive
  • CSP: style-src unsafe-inline
  • Content Security Policy (CSP) Header Not Set

Image description

What happens when the directive values 'unsafe-inline' and 'nonce-${nonce}' are set together?

Get the error:

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'unsafe-inline' 'nonce-MjNjZTAzNDEtYWMxMC00OGViLTg5NDYtZjMxOTg0ODg2MjVm'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.
Enter fullscreen mode Exit fullscreen mode

As shown in this image:

Image description

To resolve this issue, remove either 'unsafe-inline' or 'nonce-${nonce}' from the directive.

Top comments (0)