Skip to content

CSP configuration from astro-shield blocks inline styles of syntax highlighting #140

Open
@abhabongse

Description

@abhabongse

Hi Astro-Shield Maintainers!

Thanks a lot for building and maintaining Astro-Shield! It has helped me integrating CSP into my static websites.

I recently came across a very specific issue where CSP is at odds with inline style of code syntax highlighting in Astro. Here's the breakdown:

  1. Astro's code syntax highlighting (such as pre-bundled shiki or astro-expressive-code) produces the HTML output where <span> tokens that contains inline styles.

    Here is one example:

    <!DOCTYPE html>
    <style integrity="sha256-U8bvsLpPRBV22VuGGYvK6SKOwuWuIrN5tvO8jY6oZC8=">.example{font-size:18px}
    </style>
    <div class="example">Hello!</div>
    <pre class="astro-code github-dark"
         style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0"
         data-language="python"><code><span class="line"><span style="color:#F97583">def</span><span
            style="color:#B392F0"> greet</span><span style="color:#E1E4E8">():</span></span>
    <span class="line"><span style="color:#79B8FF">    print</span><span
            style="color:#E1E4E8">(</span><span style="color:#9ECBFF">"Hello, World!"</span><span
            style="color:#E1E4E8">)</span></span>
    <span class="line"></span></code></pre>
  2. I use Astro-Shield to generate SRI hashes and also use its Netlify integration to generate _headers file which, according to my understanding, contains generated CSP headers for each of the pages.

    For completeness, my configuration looks like the following:

    shield({
       securityHeaders: {
         enableOnStaticPages: { provider: "netlify" },
         contentSecurityPolicy: {
           cspDirectives: {
             "default-src": "'none'",
             "script-src": "'self'",
             "style-src": "'self' 'unsafe-inline'",
             "img-src": "'self' data:",
             "font-src": "'self' data:",
             "frame-src": "'self' https://www.youtube-nocookie.com",
             "form-action": "'self'",
             "frame-ancestors": "'self'",
             "base-uri": "'self'",
             "worker-src": "'self'",
             "manifest-src": "'self'",
             "upgrade-insecure-requests": "",
           },
         },
       },
     }),

    and the generated _headers (partial):

    /example/index.html
        content-security-policy: base-uri 'self'; default-src 'none'; font-src 'self' data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self' https://www.youtube-nocookie.com; img-src 'self' data:; manifest-src 'self'; script-src 'none'; style-src 'self' 'sha256-U8bvsLpPRBV22VuGGYvK6SKOwuWuIrN5tvO8jY6oZC8=' 'sha256-xYqUZvluhUpsRy3UdguVrRB9kJjgiW47MPZjSxEi6TI=' 'unsafe-inline'; worker-src 'self'
    

    The only thing to note from the above is this part:

    style-src 'self' 'sha256-U8bvsLpPRBV22VuGGYvK6SKOwuWuIrN5tvO8jY6oZC8=' 'sha256-xYqUZvluhUpsRy3UdguVrRB9kJjgiW47MPZjSxEi6TI=' 'unsafe-inline'; 
    
  3. Deploying this website (minimal example) on Netlify results in syntax highlighting missing their colors. The browser tells me that 'unsafe-inline' under style-src is ignored because SRI hashes (or nonce) exist. That's obvious my website contains <style> tags in other parts of the page, thus the hash was generated.

Obviously, everything is working as intended. However, I wish that Astro-Shield provides some more granular control via config over how SRI hashes are injected into CSP headers. Particularly

An option to leave style-src untouched when generating CSP headers so that my website can use 'unsafe-inline'. For example:

shield({
   securityHeaders: {
     enableOnStaticPages: { provider: "netlify" },
     contentSecurityPolicy: {
       cspDirectives: {
         "default-src": "'none'",
         "script-src": "'self'",
         "style-src": "'self' 'unsafe-inline'",
         "img-src": "'self' data:",
         "font-src": "'self' data:",
         "frame-src": "'self' https://www.youtube-nocookie.com",
         "form-action": "'self'",
         "frame-ancestors": "'self'",
         "base-uri": "'self'",
         "worker-src": "'self'",
         "manifest-src": "'self'",
         "upgrade-insecure-requests": "",
       },
       modifyCspDirectives: { // <-- added
         "script-src": true,
         "style-src": false,
       }
     },
   },
 }),

I know that 'unsafe-inline' is not the best settings to use, but using it only for style-src: but not script-src: is an acceptable risk for me. (HTTP Observatory also seems to strongly concern more about script-src:.)

Any tips, suggestions, or workaround is also appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageTracking: Needs Triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions