Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] Enable built-in transitions without 'style-src: unsafe-inline' CSP directive. #6776

Closed
wants to merge 2 commits into from

Conversation

DrCBeatz
Copy link

@DrCBeatz DrCBeatz commented Sep 27, 2021

Currently, Svelte's built-in transitions do not work when using a strict Content Security Policy (CSP)
unless the style-src 'unsafe-inline' directive is present, which is a security vulnerability in production. This happens because Svelte appends an empty CSS stylesheet to the DOM at the start of the 1st transition. This is in effect inline css, which a strict CSP won't allow without style-src 'unsafe-inline'.

A simple solution is to add a blank external stylesheet (e.g. in the same location as 'global.css') to be used for the starting transition. This PR checks for presence of an external CSS stylesheet with the title 'svelte-stylesheet' and which contains no CSS rules (i.e. a blank stylesheet). If the 'svelte-stylesheet' is not present, everything works the same as before (this also means that transitions will not work under a strict CSP without style-src 'unsafe-inline').

To implement, add the following to the Svelte project's 'index.html' file: <link rel="stylesheet" title="svelte-stylesheet" href="svelte-stylesheet.css">. Then add the blank css file specified in the href attribute (the name of the file is not important, as long as the origin is permitted in the CSP, e.g. in the same folder/location as 'global.css').

Fixes #6662.

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with [feat], [fix], [chore], or [docs].
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with npm test and lint the project with npm run lint

Test plan: (completed - e2e test) create Svelte test project displaying the 7 built-in transitions (fade, blur, fly, slide, scale, draw, and crossfade) and demonstrate they will work under a strict CSP with the changes in this PR and fail with the current version, using Mocha and Puppeteer. To run these tests run the following command in terminal npm run test -- -g svelte-styles-csp. By default these will run headless. To see the transitions in Chromium, set the headless_browser constant to true in 'tests/svelte-styles-csp/index.ts'.

(note I attempted to write a unit test for the function get_svelte_style_sheet_index() using Mocha and JSDom. After much trial and error, I discovered that JSDom does not fully implement the CSS Object Model, so certain properties of the CSSStyleSheet class needed to write a unit test for this function (which uses a StyleSheet class as a single parameter) are not present (including title and ownerNode)).

[update: added video of svelte-style-csp tests running in Chromium]

svelte-styles-csp.tests.mp4

@DrCBeatz
Copy link
Author

DrCBeatz commented Oct 2, 2021

The Windows CI tests were hanging so I was able to duplicate the issue on a VM and resolve it by adding "optionalDependencies": {"fsevents": "^2.1.3"} to package.json. FSEvents is a Mac-only optional dependency which npm in Windows was waiting for the user's response on whether to include. The tests already worked on Windows in Node 16, which apparently addressed this issue in a recent PR. As an example, below are screenshots of the tests passing on Windows with Node 12.22.6 (1st my tests and 2nd all the tests).

svelte-styles-csp_tests_node_12

svelte-styles-csp_all_tests

@DrCBeatz
Copy link
Author

DrCBeatz commented Oct 3, 2021

I did a squash-merge of the commits to clean things up and then updated .eslintignore and test/svelte-styles-csp/index.ts (which contains the code for my tests) for the linting to pass. For convenience, all of the business logic of this PR is here: src/runtime/internal/style_manager.ts (lines 21 thru 61). I also modified lines 152 to 154 of package.json as mentioned previously to keep the Windows CI tests from hanging. Hope this helps!

@DrCBeatz
Copy link
Author

DrCBeatz commented Oct 4, 2021

As an update, I tested the latest commit for this PR in my local development environment (Mac OS 14.6 on Intel 2018 Mac Mini) and on a Windows 10 Enterprise VM (v1809) using Node versions 16.10.0, 14.18.0, 12.22.6, 10.24.1 and 8.17.0 respectively. All tests passed (including the tests I wrote) on all versions of Node listed above. The only issue I had was a series of warnings when running npm install Node 8 on both Mac and Windows, which npm audit fixresolved (I can post the log file if needed but not sure it's relevant).

Not sure if the best approach here is to attempt to resolve the package-lock.json conflict first or refactor/rewrite my tests before doing another commit. Any input on this would be appreciated.

@DrCBeatz
Copy link
Author

DrCBeatz commented Oct 6, 2021

Latest commit resolves conflicts with package-lock.json and passes all tests withnpm run test and npm run lint. Also manually tested my test project in Safari, Firefox and Chrome using the current build. We'll see how this goes. If there are still issues I'll try rewriting my tests in case they aren't behaving in the automated test environment VMs/containers. Cheers!

@pzuraq
Copy link

pzuraq commented Nov 30, 2021

Any movement on this? We just ran into this issue and would definitely like a better solution than enabling unsafe-inline for our styles

@DrCBeatz
Copy link
Author

DrCBeatz commented Dec 2, 2021

Any movement on this? We just ran into this issue and would definitely like a better solution than enabling unsafe-inline for our styles

Hi Chris! I need to rewrite the tests for this PR, I will try doing that this weekend if I have time. Tests aside, the fix is 30 LOC in one file, see below in case you are interested. I've used this fork in a project utilizing transitions which received an A+ rating on Mozilla Observatory with no style-src: unsafe-inline in the CSP. Given that it's a simple fix and it seems to work, once the tests are working it shouldn't take long to review the code with any luck. All the best!

https://github.com/sveltejs/svelte/pull/6776/files#diff-0a7be6d1eea82f47b46ca98db41b2b58ab89072cf8b1a15db1187e4714f8c951

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change transitions to not require style-src 'unsafe-inline' CSP.
2 participants