I have a Google Chrome Extension where I catch headers for each web request and look for some information in the headers. The websites that I am considering are just special and a few, and they send a default content-security-policy in the 'meta' tag of the source. Which blocks any javascript:
<meta http-equiv="Content-Security-Policy" content="script-src 'none';" >
The websites also send me their real content-security-policy in the headers. In short, this content-security-policy in the headers should be taking effect after I have done with my information search in the headers. Because, after I find the information I am searching, I override the source and write the new content to the browser with document.write() with a content script sent from my browser extension.
First of all, I just don't understand which content-security-policy is taking effect where, because the source with a content-security-policy in meta tag doesn't care about the content-security-policy in the headers any more. The one in the meta tag is effective. Is that right?
Also, when I override the source with document.write() looks like no content-security-policy is taking effect any more. If I replace it in the 'meta' tag, the browser returns a warning in console saying that it had ignored it. The one in the headers is not taking effect at all.
When does the browser evaluate the content-security-policy and is it any possible to re-evaluate it? or using the document.write() is the problem here?
Related
I am trying to load jQuery in Electron (v. 16.0.0), but I get this error:
Inside the head element I have included this line:
<meta http-equiv="Content-Security-Policy" content="script-src 'self';">
Also, inside the body element, I am trying to load jQuery like this:
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
I have tried so many ways to find a solution for this, but to no avail. Previously, I also tried to load jQuery like this, but it gave me a similar error, shown below:
<script>window.$ = window.jQuery = require('./libraries/jQuery/jquery.min.js');</script>
Answers to a related question did not work for me either. What should I do?
The reason Electron, or any other Web browser that implements Content Security Policy, for that matter, would correctly refuse to load a script from an arbitrary origin (URL), or even an "inline" script (e.g. script text inside a script element), is because your security policy is explicitly specified to deny such attempts, with that meta element you said you added:
<meta http-equiv="Content-Security-Policy" content="script-src 'self';">
Why did you add it? Was it there by someone else's hand? Why is it there? It's the reason why Electron denies loading of the scripts in question.
The value of the content attribute above has the effect of instructing Electron to only allow loading scripts from the same origin as the origin of the document containing the meta element. That effectively excludes every other origin like https://code.jquery.com and inline scripts (which have to be allowed explicitly in this case because self denies these). Basically, the value is to be interpreted as "only allow loading scripts from the same site". Inline scripts are not considered as "same site".
Simpler put, you yourself prohibit loading of scripts from the kind of locations you then attempt to use, with that meta element.
You need to learn how Content Security Policy mechanism works and applies in your case. You will have to decide whether you want to allow loading of scripts from domains like code.jquery.com, or whether, for example, you will only want to allow loading scripts from your website, which in turn will probably necessitate you copying the JQuery library you want to use to be served by your website. You also will have to decide if you want to allow "inline" scripts on your site, for whatever reason you may consider necessary.
The security policy mechanism itself is very useful, don't shy away from it, it's there for a reason -- to help you prevent abuse of your site users by malicious scripts loaded by other malicious scripts or mechanisms. But you need to use it correctly, obviously.
You have 2 issues because of jQuery:
script-src 'self' does not allow to load script from https://code.jquery.com/jquery-3.6.0.min.js, that's why you observe Refused to load the script 'https://code.jquery.com/jquery-3.6.0.min.js'... error.
You have to adjust your CSP at least as script-src 'self' https://code.jquery.com;.
After page loads, the jQuery pick up all scripts having $() and place them into one inline script in the <head> section. That's why you observe Refused to execute inline script ... error.
This inline script can be resolved with either 'unsafe-inline' or 'unsafe-eval' or 'nonce-value'(for jQuery > 3.4).
Allowing 'unsafe-inline' is a very harmful advice, since such CSP will not protect against XSS at all (https://youtu.be/zlH_bBQMgkc?t=717).
Also Electron does not have the technical ability to refresh the 'nonce' value.
Therefore, the most secure CSP you can do is:
script-src 'self' 'unsafe-eval' https://code.jquery.com;
or much better:
default-src 'self'; script-src 'self' 'unsafe-eval' https://code.jquery.com;
Note: Contrary to a common misconception, 'self' does not mean the Same Origin Policy, CSP interprets 'self' much more broadly.
I am trying to understand why I am getting a Content Security Policy report of a connect-src violation from Chrome only (not Firefox) for the case where Javascript executes something like:
somediv.innerHTML = "...<img src='https://thirdpartysite/someimage.jpg'>..."
in a window.onbeforeunload handler.
I have made a little demo of the problem here: https://testcsp.savesnine.info/ . This assigns some HTML with an img element with a third-party src in both a window.onload handler (so the image shows up on page load) and in window.onbeforeunload. The onload assignment does not fire CSP, but the onbeforeunload does.
It is also firing on connect-src not img-src (I have set the img-src to allow third-party images, but not connect-src, and I don't believe I should need to, and in any case that would defeat the point). You can see the CSP header and the CSP report firing from the Chrome debugger (when you go to a different web page - it needs Preserve Log on for the console to see it, or on Network for the report being sent to /csp.php). The CSP header is:
default-src 'self';style-src 'self';img-src 'self' https:;script-src 'self';connect-src 'self';font-src chrome-extension: moz-extension: safari-extension: data:;report-uri /csp.php
This is an artifical example, but the real problem arose from a hard to diagnose CSP report which seemed to happen some minutes after people finished with the web page it happened on (according to my log files). I eventually worked out that it came from the tinymce editor when they closed the browser page (or went elsewhere), which sets a onbeforeunload handler to write the HTML it has been editing (containing third-party images, but allowed by img-src) back into the original container element the content came from.
I think I have the correct CSP for my case here, so it may be a Chrome bug, but equally I may have misunderstood something about CSP.
Let's consider the following scenario:
a user loads https://foo.com/index.html in one of the modern browsers which allow CORS.
index.html loads a javascript from https://bar.com/script.js via the script tag.
considering a hypothetical situation where this script.js is never cached and the content of script.js has changed.
script.js makes an XHR request to https://baz.com
https://baz.com has enabled Access-Control-Allow-Credentials: * thus this XHR made by script.js goes through.
important user information now can be passed to https://baz.com which is a security risk.
Prior to CORS, XHR calls were strictly followed same-origin policy and thus calls to https://baz.com from https://foo.com would not be permitted by the browsers.
I am wondering if there is a way for https://foo.com/index.html to specify a list of XHR permissible domain names so that the above scenario would not be possible.
Any pointer is highly appreciated.
[UPDATED]
I guess I have found the answer to my question.
Thank you for being considerate 🙏
Best!
I guess I found the answer to my question.
Using connect-src directive of the Content-Security-Policy Header https://foo.com/ can restrict the XHR, fetch calls along with WebSocket, EventSource, <a> ping to desired domains.
Content-Security-Policy: connect-src <source> <source>;
More information at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src
I once thought of deleting my question but someone else like me can be benefited.
CORS blocking is done on the server side, where the response headers are set to allow requests from certain origins or not.
If bar.com/script.js fetches data from baz.com, then baz.com should have the CORS restriction.
I'm write an external script for a single web page and i need to make one POST JSON request to another resource through this script.
However, when i do, it throws CSP error: "Refused to connect to <URL> because it violates the following Content Security Policy directive: "connect-src 'self'".
I looked into the web page and see meta tag which contain a Content-Security-Policy with CSP content. However, i tried manually add my <URL> to CSP connect-src content, but it is still not working.
Questions:
can i change CSP through the external script? How?
maybe any workaround for this?
The error message is saying the setting that needs to be changed:
it violates the following Content Security Policy directive: "connect-src 'self'"
So you need to set the 'connect-src' directive to something other than 'self', which might have been set by default.
You said you tried to add the URL that you're trying to connect to. That is not quite right - you need to add just the host part, rather than any of the path.
So the connect-src part of the CSP header should look like:
connect-src 'self' https://*.example.com
If you update your question with what you tried, if it still isn't working, the exact error could be diagnosed.
Is there a way to globally catch mixed content errors?
To be clear: I don't want to allow the insecure content, all I want to do is handle the error gracefully.
Backstory: I'm integrating programmatic ads, that is i have to include some script tag, which returns some more JavaScript, which can load even more resources, etc...
It is impossible for me to control, what's coming to my website and sometimes those resources include http resources, which throw a mixed content error. I#m then left with an empty ads container, which looks kind of ugly. Also, I could try to resell this ad-space, since the first try failed.
I already tried window.onerror, but with no avail.
There is no way to catch mixed content warnings, as they have no relation to JavaScript and are handled by your browser instead.
What you can do instead is use Upgrade-Insecure-Requests header to prevent browser from loading unsafe content entirely. And, depending on your use case, you may use MutationObserver to react to changes in your HTML, or listen to Error Events on document.body during capture phase to react to errors:
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests"
/>
</head>
<body>
<script>
const el = document.createElement("img");
el.src = "http://unsafeimg";
document.body.appendChild(el);
document.body.addEventListener(
"error",
(err) => {
console.log("Failed to load\n", err.target);
},
/* Notice the true value here. It is required because Error Events do not bubble */
true
);
</script>
</body>
</html>
Another option would be to set up a Service Worker to intercept and handle insecure requests. This is probably the best solution, as this gives you full overview of what data your website it trying to load.
Sounds like you are having an issue specifically revolving around fixing mixed content policies. There are many approaches to tackle and arrive at a solution.
My recommendation is to go off some documentation provided and referenced by Google: https://web.dev - Fixing Mixed Content.
Mixed content occurs when initial HTML is loaded over a secure HTTPS connection, but other resources (such as images, videos, stylesheets, scripts) are loaded over an insecure HTTP connection. This is called mixed content because both HTTP and HTTPS content are being loaded to display the same page, and the initial request was secure over HTTPS.
First off mixed content will occur when such initial-based HTML is transferred over the network through a secure HTTPS connection. Although, the problem arises when other resources as you stated such as:
Images
Videos
Stylesheets
Scripts
...are loaded over an insecure HTTP connection. This is the definition of a mixed content issue described. It is because of an issue pertaining to assets both HTTP and HTTPS content that is being requested and loaded to display on the website of the desired origin. And the main issue is the initial request was originally sent over secure over the HTTPS protocol.
Note: Before continuing, when requesting any of these subresources overusing the insecure HTTP transfer protocol, will open up vulnerabilities of the entire origin site. Such vulnerability attacks are named on-path attacks.
Depending on the browser your website user base is primarily targeting, there are fixes and preventions to take note of being rolled out by browsers such as Google Chrome. Which will upgrade passive mixed content where it is possible. Such a process will be deciding if the resource asset is available over HTTPS, but determine if it was created to be served over the HTTP protocol, the browser will load the HTTPS version instead. So in conclusion, it will disregard the HTTP resource.
Content Security Policy (CSP)
You need to reference the below section of https://web.dev - Fixing Mixed Content linked here. It will allow you to utilize a browser-based implementation that may be used to solve and manage mixed content issues. Which allows and opens up opportunities for different enforcement policies to be implemented.
To enable CSP, you have the opportunity to set up your site to return the Content-Security-Policy HTTP header. Which has replaced the X-Content-Security-Policy older policy.
My suggestion is to make use of the <meta> HTML element. This will allow you to customize which domains you trust in regards to CSP in general and implement different customizations using this element.
This is an example where you do wish to allow any resource content from a trusted domain, and you may use alternative formatting to allow sub-domains and other aspects to grant desired outcomes. Notice the formatting, following the subdomain setting.
Content-Security-Policy: default-src 'self' example_trusted.com *.example_trusted.com
So when utilizing this, you may take an approach for certain resources such as advertisements or images you decide to trust, but must be set up appropriately.
One vague example might be, without an asterick:
content="default-src 'self' https://example.com http://example.com:80/images/"
This concludes a result conclusive of:
https://example.com # Correct
http://example.com/images/ # (Missing) Incorrect Port
http://example.com:80/images/image.jpg - Correct Port
https://example.com:81 # (Missing) Incorrect Port
You may use approaches like these referenced here at Mozilla - Content-Security-Policy, which may help form a solution.
Or just go completely vulnerable.
content="default-src * 'unsafe-inline' 'unsafe-eval'"
Many references on StackOverflow such as How does Content Security Policy (CSP) work?, which was referenced in this post. Hope I was of some help.
Complete References List:
https://web.dev/fixing-mixed-content/
https://web.dev/fixing-mixed-content/#content-security-policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
How does Content Security Policy (CSP) work?
What I do whenever dealing with mixed content is updating the .htaccess file with the following:
Header always set Content-Security-Policy: upgrade-insecure-requests
That should by take care of the mixed content and make sure that you load everything trough HTTPS.