I'm looking for a good way to implement a relatively strong Content-Security-Policy header for my ASP.NET WebForms application. I'm storing as much JavaScript as possible in files instead of inline, but by default, WebForms injects a lot of inline scripts—for things as simple as form submission and basic AJAX calls.
MVC has some simple ways to implement nonces, especially with the help of third party libraries like NWebsec, but I can't seem to find any methods of implementing them with WebForms. I wouldn't even have a problem using hashes if there were a way to predict and retrieve the hash for each .NET injected script tag.
I hate allowing the 'unsafe-inline' value. It feels wrong needing to turn off such a powerful security feature. Is there a reasonable way to implement it in WebForms?
I had the same problem. I'm sad to say this was the best we have done. We basically identified what we use and don't use. We even had to put unsafe-eval in some instructions because we were using third party controls that couldn't work without it. At least we avoid calls to external urls.
default-src 'self';
child-src 'self' 'unsafe-inline' 'unsafe-eval';
object-src 'none';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com;
img-src 'self' https://www.google-analytics.com;
style-src 'self' 'unsafe-inline'
I wrote an answer here for what to do about all those injected scripts:
If you open up the dev tools in Chrome, you'll likely see a message like
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'. Either the 'unsafe-inline' keyword, a hash ('sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II='), or a nonce ('nonce-...') is required to enable inline execution.
If you look carefully at that message, it's telling you what the hash would be: sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II=
So if you don't want to go the nonce route, you can instead go the hash route and add
Content-Security-Policy: script-src 'self' 'sha256-2NqnatcPqy5jjBXalTpZyJMO/0fUaYUb3ePlviUP4II=' 'unsafe-eval';
You may have to add unsafe-eval in some cases as well for this to work.
Let's start with a simple example:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy" value="default-src 'self'" />
</customHeaders>
</httpProtocol>
</system.webServer>
The value of the Content-Security-Policy header is made up of N segments separated by a semicolon. In the example above, we only specify a single segment, saying "only load resources from 'self'". 'self' translates to the same origin as the HTML resource. With this minimum configuration, your HTML is allowed to fetch JavaScript, stylesheets etc. from the same domain that served the HTML referencing the resources. You won't be able to include external scripts from CDNs and similar.
Let's say that you host everything yourself, but want to include jQuery from cdnjs. You would need the following value to allow the browser to make requests outside your origin:
<add name="Content-Security-Policy" value="default-src 'self' https://cdnjs.cloudflare.com" />
Remember the segments I talked about? You can configure which domains to load different kind of resources from using a range of different *-src keys like this:
<add name="Content-Security-Policy" value="default-src 'self'; script-src 'self' https://cdnjs.cloudflare.com; style-src 'self' https://maxcdn.bootstrapcdn.com" />
This configuration let your web application load resources from its own domain, plus scripts from cdnjs.cloudflare.com and stylesheets from maxcdn.bootstrapcdn.com.
We also had to tighten
default-src 'none';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
img-src 'self' data:;
style-src 'self' 'unsafe-inline' 'unsafe-eval';
connect-src 'self';
font-src 'self';
frame-ancestors 'none';
This solution works well with ASP.NET WebForms as it still allows inline (no need to extract everything to separate js files) as well as eval's.
Unsafe-Tags are specifically needed to provide better WebForms Functionality in my opinion.
To see if you need any additional/less Restrictions you can use:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
Related
I'm building a NextJs application, and I'm trying to set a secure header in my project's next.config.js file. and every time i request to google like adsense and other default google services it is also blocked, is there a way to handle this, so that it is not blocked
this is my code
const ContentSecurityPolicy = `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline' *.google.com *.doubleclick.net *.googleadservices.com *.googlesyndication.com *.googletagmanager.com *.google-analytics.com;
There are likely two root problems or your errors:
An error message says "Content Security Policy: Duplicate script-src directives detected. All but the first instance will be ignored." As the CSP you shown does not have duplicate script-src, it could be from another CSP. CSP can be defined in both response header and as a meta tag. Check both and see if one of them has multiple script-src defined. It is ok to have multiple CSPs with one script-src each. As content has to pass all policies, another CSP can only make it stricter.
You have not defined frame-src. There are errors due to iframes, and they fall back to default-src in your CSP, which only allows 'self'.
Refused to execute a script because its hash or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
This is happening with Google Ads. My Nginx has:
add_header Content-Security-Policy "frame-ancestors 'self'";
What do I add/change to fix that error so my google ads show?
There are likely multiple CSPs active, and all content needs to pass all policies. Check the response headers and meta tags for other CSPs and modify/remove them to have a single CSP.
We are getting security issue due to unsafe-inline in header and as per security team we should use nonce but that one is difficult to use with inline event handler method so we are looking for the option to use 'self' instead of nonce
Inline event handlers are not nonceable elements, so you can't allow them with a nonce. Your options are to use 'unsafe-inline' or to rewrite event handling into a file on your server, for which you would need 'self' to load. Adding 'self' will allow files under that directive to load, but will not allow inline event handlers directly.
I'm using nginx to set the CSP header.
I often see this in examples:
default-src 'self' http: https: data: blob: 'unsafe-inline' 'unsafe-eval' https://*.foo.com;
I understand that https://*.foo.com allows loading from the foo.com domain.
But what is the meaning of the "empty" http: and https: declarations?
It means allow content from all sites on that protocol. For example:
https://example.com
https://www.example.com
https://www.google.com
http://www.google.com
http://evilhacker.com
That policy, as it currently stands, basically allows everything and is pretty pointless!
I am using an iframe to show a calendar on it. But I keep getting the following;
Refused to display 'https://cal.mixmax.com/user1' in a frame because
an ancestor violates the following Content Security Policy directive:
"frame-ancestors 'self' https://mail.google.com
https://inbox.google.com https://.force.com https://.mixmax.com".
I tried to have the meta for Content-Security-Policy as the following but no luck.
<meta http-equiv="Content-Security-Policy"
content="frame-ancestors 'self'
https://mail.google.com
https://inbox.google.com
https://*.force.com
https://*.mixmax.com">
Any idea how to overcome it?
The problem is not a misconfiguration on your side, it's on the CSP directive on Mixmax side. They have the following directive on their page:
content-security-policy:
frame-ancestors 'self'
https://mail.google.com
https://inbox.google.com
https://*.force.com
https://*.mixmax.com;;
frame-src:
https://*.stripe.com
https://*.facebook.com
https://*.mixmax.com;;
So you cannot frame it, unless you are from any of the listed domains.
One way to overcome that is to create a proxy on your site, access MixMax on the behalf of the client, and send the data to your frame, as CSP is client-enforced only.