hotwired / turbo

The speed of a single-page web application without having to write any JavaScript
https://turbo.hotwired.dev
MIT License
6.65k stars 421 forks source link

Apply CSP nonce when createElement is called #602

Open michaelbudd1 opened 2 years ago

michaelbudd1 commented 2 years ago

Hi!

Firstly, thanks for your work on this project! 👋

Today I used patch-package to patch @hotwired/turbo@7.1.0 for the project I'm working on.

There is an issue which is documented here https://github.com/hotwired/turbo/pull/501/files but that fix doesn't exist in this file.

Here is the diff that solved my problem:

diff --git a/node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js b/node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
index 963422f..1b164fe 100644
--- a/node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
+++ b/node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
@@ -1215,6 +1215,9 @@ class ProgressBar {
         const element = document.createElement("style");
         element.type = "text/css";
         element.textContent = ProgressBar.defaultCSS;
+
+        element.nonce = document.head.querySelector('meta[name="csp-nonce"]')?.getAttribute('content')
+
         return element;
     }
     createProgressElement() {

This issue body was partially generated by patch-package.

dhh commented 2 years ago

We haven't generated a new release yet. Will soon.

gucki commented 1 year ago

@dhh I am using turbo-rails (1.3.2) and it seems the issue is still occuring:

turbo.es2017-esm.js:1443 Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https:". Either the 'unsafe-inline' keyword, a hash ('sha256-WAyOw4V+FqDc35lQPyRADLBWbuNK8ahvYEaQIYF1+Ps='), or a nonce ('nonce-...') is required to enable inline execution.

loadWidgetCss.js:24 Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https:". Either the 'unsafe-inline' keyword, a hash ('sha256-ZlKrV4l7+FEqK6MLE9/by6VkzUMyZsFi9lRmaK6EeIA='), or a nonce ('nonce-...') is required to enable inline execution.

The <meta name="csp-nonce"... is of course present in the head section of the page.

Or is another issue?

dhh commented 1 year ago

@rience Could you have a look?

rience commented 1 year ago

This is happening because style-src is missing from default nonce directives. There's PR https://github.com/rails/rails/pull/46141 merged to Rails main on October 12 waiting to be released.

@gucki to fix your problem - open content_security_policy.rb and fix this line

# change this
config.content_security_policy_nonce_directives = %w(script-src)

# to this
config.content_security_policy_nonce_directives = %w(script-src style-src)
gucki commented 1 year ago

Hi @rience , thank you very much for your quick response. I can confirm that adding "style-src" to content_security_policy_nonce_directives fixes the first issue (turbo.es2017-esm.js:1443), but the second issue still occurs (loadWidgetCss.js:24).

rience commented 1 year ago

Hi @gucki,

Is loadWidgetCss.js script you've written? I couldn't find that in turbo repository.

However, what I think might be happening is that you didn't add nonce attribute when adding loadWidgetCss.js. You can do that by passing nonce: true to helper. Something like this might help?

<%= javascript_include_tag 'loadWidgetCss', nonce: true %>
gucki commented 1 year ago

Hi @rience, no I didn't write it. And I'm using only "standard" gems, that's why I thought this one is part of turbo too. But most probably it's part of tailwindcss-rails then, I'll investigate. These are the gems I'm using:

gem "rails", "~> 7.0"
gem "rails-i18n"
gem "sprockets-rails"
gem "puma"
gem "tailwindcss-rails"
gem "haml"
gem "email_validator"
gem "importmap-rails"
gem "turbo-rails"
gem "stimulus-rails"

gem "terser"

gem "rouge"
gem "kramdown"
gem "kramdown-parser-gfm"
gucki commented 1 year ago

@rience Searching through github shows a few matches, for example https://github.com/HamzaShah101/Itechseries/blob/dba1262ee0f690f9947fe884d40b7c658fcec0bd/webpack---/js/utils/loadWidgetCss.js.

But searching in the original webpack repository https://github.com/webpack/webpack/search?q=loadWidgetCss doesn't yield any results. Interesting...

And I'm not even using webpack in this project…

rience commented 1 year ago

Here's what I could suggest you to do

  1. Open web developer console and click link to loadWidgetCss.js - you'll probably see a code that is building style tag.
    • You might consider adding code that is reading csp tag from head and apply to that style element e.g. element.nonce = ''
  2. While looking at loadWidgetCss.js - take a look at top of this file - maybe you'll find information where does it come from
gucki commented 1 year ago

Unfortunately, the file doesn't contain any helpful comments. But I'll find out anyway ;-) But thank you very much for your help. I think we are done here, as the initial issue with turbo.es2017-esm.js is resolved by your fix.

msneujink commented 1 year ago

I've got the same issue. Adding strict-dynamic to the script-src security policy fixes the issue with turbo.es2017-esm.js for me.