You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using hash-based CSP I stumbled upon a problem with inlined scripts and the way how browsers evaluate them.
As per documentation The script loads from src and doesn't have an integrity attribute: The script will be replaced by an inline proxy script that loads the script.
Without CSP middleware, in Next.js projects, we have scripts defined like this
And after applying hash-based (getStaticProps) CSP they become
<script id="5zbJ2CSN5ZHJ7kI3HCjNak1kgqgXaui0lVxMh708sXY=" integrity="sha256-OS+aC92nKNx/83Md8ClJLpS9XT14tdjffxW8qX0l+tY=">
(function() {
var s0 = document.createElement('script');
s0.async = false;
s0.defer = true;
s0.src = '/_next/static/chunks/webpack-bbd44435dc4b036d.js';
var s1 = document.createElement('script');
s1.async = false;
s1.defer = true;
s1.src = '/_next/static/chunks/framework-5f4595e5518b5600.js';
.....
var s = [s0, s1,........];
var self = document.getElementById('5zbJ2CSN5ZHJ7kI3HCjNak1kgqgXaui0lVxMh708sXY=');
var p = self.parentNode;
p.removeChild(self);
s.forEach(function(si) {
p.appendChild(si);
});
}
)()
</script>
For statically defined scripts (so-called parser-inserted scripts) "defer" tag delays the evaluation of the script till the DOM is retrieved and fully parsed. However, for dynamically added scripts "defer" is not taken into account, and scripts are executed right after the parser has parsed them and doesn't wait for DOM to be fully parsed.
So transformation that CSP middleware executes doesn't guarantee the same semantics as the origin.
Specifically, in Next.js case, I started to have problems with __NEXT_DATA__ data block after adding CSP to the project. __NEXT_DATA__ contains page props used for hydration and is placed at the bottom of the page.
For pages where __NEXT_DATA__ is really large, Next.js scripts start to access this element before it is available in the DOM, because "defer" doesn't work for dynamically inserted scripts and it breaks the whole page.
I don't have a solution yet, but perhaps this proxy script above should contain some logic to append scripts to the DOM after the DOM is loaded, to simulate "defer" logic.
<script id="5zbJ2CSN5ZHJ7kI3HCjNak1kgqgXaui0lVxMh708sXY=" integrity="sha256-OS+aC92nKNx/83Md8ClJLpS9XT14tdjffxW8qX0l+tY=">
(function() {
window.addEventListener("load", function() {
var s0 = document.createElement('script');
s0.async = false;
s0.defer = true;
s0.src = '/_next/static/chunks/webpack-bbd44435dc4b036d.js';
var s1 = document.createElement('script');
s1.async = false;
s1.defer = true;
s1.src = '/_next/static/chunks/framework-5f4595e5518b5600.js';
.....
var s = [s0, s1,........];
var self = document.getElementById('5zbJ2CSN5ZHJ7kI3HCjNak1kgqgXaui0lVxMh708sXY=');
var p = self.parentNode;
p.removeChild(self);
s.forEach(function(si) {
p.appendChild(si);
});
});
}
)()
</script>
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
When using hash-based CSP I stumbled upon a problem with inlined scripts and the way how browsers evaluate them.
As per documentation
The script loads from src and doesn't have an integrity attribute: The script will be replaced by an inline proxy script that loads the script.
Without CSP middleware, in Next.js projects, we have scripts defined like this
And after applying hash-based (getStaticProps) CSP they become
For statically defined scripts (so-called parser-inserted scripts) "defer" tag delays the evaluation of the script till the DOM is retrieved and fully parsed. However, for dynamically added scripts "defer" is not taken into account, and scripts are executed right after the parser has parsed them and doesn't wait for DOM to be fully parsed.
So transformation that CSP middleware executes doesn't guarantee the same semantics as the origin.
Specifically, in Next.js case, I started to have problems with
__NEXT_DATA__
data block after adding CSP to the project.__NEXT_DATA__
contains page props used for hydration and is placed at the bottom of the page.For pages where
__NEXT_DATA__
is really large, Next.js scripts start to access this element before it is available in the DOM, because "defer" doesn't work for dynamically inserted scripts and it breaks the whole page.I don't have a solution yet, but perhaps this proxy script above should contain some logic to append scripts to the DOM after the DOM is loaded, to simulate "defer" logic.
Beta Was this translation helpful? Give feedback.
All reactions