I am working on an extension that will inject some elements into the webpages using content scripts.
i used react/webpack to build the extension. but when i am trying to use the extension, in some websites like secure.login.gov the styles are not getting injected. i am getting the following error in console.
Content-Security-Policy: The page’s settings blocked an inline style (style-src-elem) from being applied because it violates the following directive: “style-src ‘self’ https://secure.login.gov ‘nonce-83e27ef5530a894f4f0ee9c5323940ea’
there is no issue in chrome/edge where i am using manifest v3 where as in firefox i am using manifest v2.
i tried instructions in here https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy. but this looks like will be applied to extension pages not the actual web pages
any help on this will be appreciated.
The answer is that there sort of is no answer. It is a longstanding bug in Firefox that CSPs should not apply to extensions. It's not a v2 vs v3 thing. It's Firefox vs Chrome. (FWIW, I also feel the pain.)
Page CSP should not apply to content scripts
Override page CSP for content scripts
You are correct when you interpret the MDN Browser Extension page on CSPs to mean it's the CSP that an extension applies to itself (i.e., to protect the extension integrity). However, because of the bug, web page CSPs are applied to extensions, as well.
In your example, the style has to have the specified nonce or to be loaded from either the page origin ('self') or secure.login.gov.
When a nonce'd script or style tag is loaded into the DOM, the nonce is stripped, so malicious code (and beneficent developers) cannot get the nonce from the DOM. To listen for the response headers to parse the CSP header for a nonce, run something like the code below in the background, send the nonce values to the tab, then include those nonces in the tags you want to insert. That's not a solution that will work everywhere, because different sites could have different restrictive CSPs.
( function () {
'use strict';
var
nonce = {}; // nonces for each tab ID main frame
// get script and style nonces, if they exist
// from the csp header, if it exists
function onHR( e ) {
var
h = e.responseHeaders,
id = e.tabId,
src, a, i, j;
for ( i = 0; i < h.length; ++i ) {
if ( h[ i ].name.toLowerCase() === 'content-security-policy' ) {
src = h[ i ].value.split( ';' );
for ( j = 0; j < src.length; ++j ) {
a = src[ j ].match( /^[^']*?script-src.*'nonce-(.*?)'/ );
if ( a ) {
nonce[ id ] = nonce[ id ] || {};
nonce[ id ].script = a.pop();
}
a = src[ j ].match( /^[^']*?style-src.*'nonce-(.*?)'/ );
if ( a ) {
nonce[ id ] = nonce[ id ] || {};
nonce[ id ].style = a.pop();
}
}
}
}
}
browser.webRequest.onHeadersReceived.addListener(
onHR, {
types: [ 'main_frame' ],
urls: [ '*://*/*' ]
}, [
'responseHeaders'
]
);
} () );
A full-blown background should do more careful bookkeeping on the nonce
object.
In the content context on secure.login.gov, (less ambitiously) inserting a tag without the nonce, getting the CSP violation to find the value of the nonce, then trying again with that nonce shows that it can be done.
// nothing fancy
( function () {
var
style = document.createElement( 'style' );
document.head.appendChild( style ); // fails
style.nonce = '03ab2ecf4cdea6878b43dfe91fbfb0db'; // this time
document.head.appendChild( style ); // succeeds
} () );