mailto href inside frame not working when Content Security Policy - iframe

Summary:
Site at https://localhost:3000 , with Content-Security-Policy value of default-src 'self' 'unsafe-inline' https://localhost:3001/https_index.html contains iframe pointing at https://localhost:3001/index.html. The contents of :3001/index.html contain an . Clicking that link fails: Refused to frame '' because it violates the following Content Security Policy directive.... How can I change my CSP value to prevent this error; to open an new email in user's preferred email client (normal behavior of mailto)? I am using Chrome1
Detail:
Similar but different than this question "mailto link not working within a frame chrome (over https)
"
I think mine is not a duplicate because:
I cannot reproduce that bug, I see a console warning about mixed-content when I try to reproduce their steps:
Mixed Content: The page at 'https://localhost:3001/https_index.html' was loaded over HTTPS, but requested an insecure resource 'mailto:...'. This content should also be served over HTTPS.
My steps are specific; both my page & its iframe src are https, but the page itself is served with a specific and restrictive Content-Security-Policy (CSP):
app.use(csp({
directives: {
defaultSrc: ["'self' 'unsafe-inline' https://localhost:3001/https_index.html"]
}
}));
Also the resulting error I can reproduce is different:
Refused to frame '' because it violates the following Content Security Policy directive: "default-src 'self' https://localhost:3001/https_index.html". Note that 'frame-src' was not explicitly set, so 'default-src' is used as a fallback.
With an image like:
The accepted answers for the original questions will help me work around my CSP-specific issue, that is, if I add a target="_top" to the link, the email client opens without error:
<a target="_top" href="mailto:...">email</a>
A similar fix works for another similar but different issue. However, this may1 sometimes open a new tab
So my question is specifically about the Content-Security-Policy error (see above):
...Refused to frame '' because it violates the following Content Security Policy directive: ...
Notice it says frame ''. The frame is identified as an empty string!
Normally if some resource violates CSP, the URL of the resource is identified; i.e.
Refused to laod the script 'http://evil.com/evil.js'...
And if the CSP-violating URL is identified + provided I can use it; add it to my CSP value for default-src:
`app.use(csp({
directives: {
defaultSrc: ["http://evil.com/evil.js 'self' 'unsafe-inline' https://localhost:3001/https_index.html"]
}
}));`
But can I allow an exception for an href value? Specifically for mailto? I tried wildcards like mailto*, but:
The source list for Content Security Policy directive 'default-src' contains an invalid source: 'mailto*'.
And I wonder if any wildcard would work anyway; does Chrome really consider the href="mailto..." frame as an empty string? I suppose so, since it's not a URL per se; Chrome "wants" to launch an external application (i.e. Outlook) in the context of the iframe; who is bound to the CSP rules of its parent page...
Footnotes:
Chrome displays the above errors in CSP or sandbox cases. Internet Explorer doesn't complain about an iframes href, despite the value of CSP. Internet Explorer also doesn't have the "new tab" problem, despite the value of sandbox. IE 11.1914 will just give message:
The fix of using target="_top" may open a new tab , if you've sandboxed your iframe! (sandbox is different than CSP). I don't like the new tab. Chrome gave me this error...
Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://localhost:3000/' from frame with URL 'https://localhost:3001/index.html'. The frame attempting navigation of the top-level window is sandboxed, but the flag of 'allow-top-navigation' or 'allow-top-navigation-by-user-activation' is not set.
... but opened a new tab, as well as the Outlook email client...
I did what the error suggested; modifying the value of the iframe sandbox attribute:
sandbox="allow-top-navigation allow-same-origin ...", and the mailto link worked (as before), but did not open an excessive new tab. Great!

Stumbled upon this question after encountering the same issue. There is surprisingly little documentation about this after hours of searching.
My first instinct was to do something like you were doing, mailto* or mailto:*.
What finally ended up working was omitting the wildcards, and altering the frame-src directive as such:
frame-src 'self' mailto: tel: *.mydomain.com
tel: links were also were broken in iframes.

Related

Google form embedded code not working after click Clear Form

When I use Google form embedded code then it's working fine. But when i click on Clear Form button then it has redirected to the original google form URL without "?embedded=true" parameter.
So, we will get this error
[Report Only] Refused to frame 'https://docs.google.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'none'".
Let me know How can i solve it?
Your page is being framed by docs.google.com. If you want to allow that you will need to set the following directive instead: "frame-ancestors docs.google.com;"

Is Content-Security-Policy header applicable only for text/html Content-Type?

From the OWASP's website
https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html:
Send a Content-Security-Policy HTTP response header from your web server.
Content-Security-Policy: ...
Using a header is the preferred way and supports the full CSP feature set. Send it in all HTTP responses, not just the index page.
I don't understand how that could be true as it is possible to set the Content-Security-Policy by using a meta tag in the HTML.
I also don't see how the policy can apply to anything else but HTML pages.
Does anyone have idea why that statement above was made and if it is safe to only send HTTP header Content-Security-Policy for text/html responses?
By the way, the policy is too big and I would like to sent as fewer bytes as possible.
This is still something that’s not formally specified and there ai still some debate on this: https://github.com/w3c/webappsec/issues/520
In general there’s two arguments here:
On the one hand some other file types (XML, PDF, perhaps even SVGs) could benefit from CSP and any resource could become the page by right clicking and opening in a separate tab.
On the other hand CSPs can get quite big and are usually written for HTML pages. So a bit wasteful to send on other resources and most of it won’t be relevant.
The right answer (as suggested by above) is probably to have a reduced, and very strict, CSP for all non-HTML responses.
But I think for most people having it on the HTML only will be good enough and bring most of the benefits of CSP. Then again CSP is an advanced technique so if going as far as that, then why not do it properly?
Using a header is the preferred way and supports the full CSP feature set.
I don't understand how that could be true as it is possible to set the Content-Security-Policy by using a meta tag in the HTML.
Inside the meta tag are not supported the directives:
report-to and report-uri
frame-ansectors
sandox
Also meta tag does not support Content-Security-Policy-Report-Only feature, only the Content-Security-Policy.
All resources that start loading before meta tag in the HTML code are not affected by CSP. Malicious scripts can be injected as first item of the <head> section just before meta tags
The nonce-value is exposed in meta tag therefore can be easely stealing by script and reuse.
Using meta tag you can only set the CSP for HTML pages, but CSP is applied for XSLT in the XML pages, and for some other kinds of content (see below).
Therefore indeed an HTTP header is the preferred way to delivery CSP and using CSP via meta tag does not allow you to use full CSP feature set.
Send it in all HTTP responses, not just the index page.
I also don't see how the policy can apply to anything else but HTML pages.
The specification had in mind a little different - you should send CSP with any response page with HTML content, not only for 200 OK, but even for 404 Not found
403 Access Forbidden, etc.
Because these pages has access to cookie that can be steal in the page not covered by CSP.
CSP is applied not only to HTML pages, but to XSLT in XML-pages, to external javascripts files for workers (in Firefox). Also frame-ancestors directive of CSP HTTP header applies to any content (JPEG/GIF/PNG/PDF/MP4/etc) intended to be embedded into iframe, see the nitty-gritty here.

How to fix "Blocked a frame with origin "https://example.org" from accessing a cross-origin frame."

For my personal use, I'm trying to show https://maps.google.com inside an iframe. Note: I am NOT looking to use Google's Embed API.
Here's what I've done:
use a Chrome Extension to remove the following request headers: X-Frame-Options, Access-Control-Allow-Origin, Access-Control-Allow-Methods
add instead these headers: Access-Control-Allow-Methods: *, Access-Control-Allow-Origin: *, Content-Security-Policy: frame-ancestors *;
the above is done on ALL request headers on ALL urls (browser.webRequest.onHeadersReceived.addListener in my extension), it's super permissive, but for now I'm just trying to make it work.
Now I'm trying to do <iframe src=" https://maps.google.com" />.
It works half-way:
I see Google Maps showing on my iframe
But there's a permanent "Loading..." text on the bottom, and I cannot click on markers or search stuff (see screenshot).
I get the following error in the console:
Blocked autofocusing on a form control in a cross-origin subframe.
maps:13 Uncaught DOMException: Blocked a frame with origin "https://www.google.com" from accessing a cross-origin frame.
at Object._.Hr (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:210:51)
at /maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=vwr,vd,a,owc,ob,sp,en,smi,sc,vlg,log,smr,as,wrc/rt=j/d=1/ed=1/exm=sc2,per,mo,lp,ti,ds,stx,bom,b/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:3599:3
at /maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=vwr,vd,a,owc,ob,sp,en,smi,sc,vlg,log,smr,as,wrc/rt=j/d=1/ed=1/exm=sc2,per,mo,lp,ti,ds,stx,bom,b/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:4990:3
at NLa (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1677:132)
at LLa.next (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1676:469)
at IIa.f [as H] (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1561:184)
at RIa (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1556:332)
at eJa (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1565:43)
at vA.Ma (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1564:405)
at mb (https://www.google.com/maps/_/js/k=maps.m.en.dc5HEiFGHqQ.O/m=sc2,per,mo,lp,ti,ds,stx,bom,b/rt=j/d=1/rs=ACT90oFcxIV8Ad7kvBMCB_zNoSobKCZYEw:1563:293)
Any ideas on what I could try next to make this work? Or is it just plainly not possible?
Short Answer: This can't be done.
Long Answer: X-Frame-Options is decided at the server side. What this means is, the one opening the page doesn't decide if document can be opened in iframe, instead author of document decides it. In this case, its Google.
I tried achieving the same thing way back with Google search where you type a word in text box and hitting submit will pop an iframe with Google results. I did some research and learned it can't be done since Google doesn't allow different origins to display their pages.
That's why they have APIs.
More about this - How to show google.com in an iframe?

Getting "Refused to apply inline style because it violates the following Content Security Policy" error

I am getting the below error while running the application
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/ 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' 'sha256-5uIP+HBVRu0WW8ep6d6+YVfhgkl0AcIabZrBS5JJAzs='". Either the 'unsafe-inline' keyword, a hash ('sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ='), or a nonce ('nonce-...') is required to enable inline execution.
Below is the code currently I am using
const string modernizrHash1 = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
const string modernizrHash2 = "sha256-5uIP+HBVRu0WW8ep6d6+YVfhgkl0AcIabZrBS5JJAzs=";
app.UseCsp(options => options
.DefaultSources(s => s.Self())
.ScriptSources(s => s.Self().CustomSources("https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/"))
.StyleSources(s => s.Self().CustomSources("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/", modernizrHash1, modernizrHash2))
.FontSources(s => s.Self().CustomSources("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/"))
.ImageSources(s => s.Self().CustomSources("data:"))
);
The hash 4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ= is for the CSS word-wrap: break-word; white-space: pre-wrap;, the inline style Chrome automatically applies when you are not serving a HTML document;
Example server response:
Content-Type: text/plain; charset=utf-8
Content-Length: 9
Content-Security-Policy: default-src 'self'
Date: Thu, 04 Nov 2021 11:33:49 GMT
some text
DOM in Chrome
<html><head></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">some text</pre></body></html>
Console error
Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self'"
. Either the 'unsafe-inline' keyword, a hash ('sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.```
Adding the hash to default-src or style-src won't help because it is an "inline style" and "hashes do not apply to style attributes".
The best fix is to make sure you serve a proper HTML document with your CSP header, so browsers don't decorate it with their own styling.
You are getting this error because the inline styles (which can be hashed to sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ=) aren't allowed, as per your Content Security Policy and the error that is returned.
I would recommend two possible steps, either:
Move away from inline styles (as they can be insecure) and will require you to change your CSP each time that the inline styles change.
Add the supplied SHA to the StyleSources for your CSP. But Be aware that this will have to be maintained and updated for each inline style added across all pages in your application.
UPDATE based on comments below answer
Note: There is no issue when i am running it in IE browser, only in the chrome and firefox i am getting the issue
Taking a look at Can I Use shows that IE has only partial support for Content Security Policy, which would explain why you aren't seeing this error in the console. i.e. Internet Explorer doesn't support CSP, so it isn't applying it.
I have fixed the issue by changing the hash keys shown in the browsers console error, I have replaced the console error hash key with my code hash key, but not sure whether this is the permanent solution or not
This is not really a permanent solution. If (and when) your inline styles change, you will have to change the hash in your CSP in order for the styles to be applied again.
Which leads me on to:
Could you please guide me how the hash keys are getting generated and how i can fix this permanently
Looking at the code in your original question:
const string modernizrHash1 = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
const string modernizrHash2 = "sha256-5uIP+HBVRu0WW8ep6d6+YVfhgkl0AcIabZrBS5JJAzs=";
// other things
.StyleSources(s => s.Self().CustomSources("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/", modernizrHash1, modernizrHash2))
You are telling the browser (via the Content Security Policy that you are generating) that it is only permitted to load styles from:
self (the origin domain of your site)
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/
and those which match the following hashes:
sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
sha256-5uIP+HBVRu0WW8ep6d6+YVfhgkl0AcIabZrBS5JJAzs=
You mention that you've also included the hash:
sha256-4Su6mBWzEIFnH4pAGMOuaeBrstwJN4Z3pq/s1Kn4/KQ=
When the browser starts to render the page, it will look at the resources that the page requires in order to render and will compare it to the list in the Content Security Policy. If a resource (inline styles and inline javascript are classed as a resource) is not in the list, then the browser will do a simple SHA-2 of the contents of the resource and compares it to any of the hashes listed in the CSP.
Note: the same thing can be achieved by the use of a nonce
If the resource isn't from an allowed source, or it's hash does not match those listed in the CSP, then the browser will actively refuse it.
Because the SHA-2 algorithm uses the content of the resource to generate the hash, when the contents of it changes the calculated value of the hash will be different.
For example, the inline style here:
<p style="color: red;">hello, world</p>
might hash to F1FF77E5DDBB1AF52EB51C98F725927143221549385937595112128987CF39E4 (which is the hash of "color:red")
whereas the following inline style:
<p style="color: green;">hello, world</p>
might has to 2F262B22412B633D12B27FA9F94A3B0495821CB8341CFF0A88C80E3FED5DC9E8 (which is the hash of "color:green")
As you can see, there is a massive difference in the hashed styles. This is by design (in the algorithm).
To stop alleviate this problem, I would swap the inline styles for a css file describing how the content of the page should be styled. As long as the css file is served from the same origin as your HTML, then the self rule will cover it.
CSP is a pretty complex topic to pick up (but easy to master, once you have learned the basics). I would recommend taking a look at the MDN page for Content Security Policy for more information on how it works and how you can use it to secure your web applications.

Content Security Policy directive: "frame-ancestors 'self'

I am embedding an iFrame in my web page, something like this:
var iframeProps = {
'data-type': self.props.type,
allowTransparency: self.props.allowTransparency,
className: self.props.className,
frameBorder: self.props.frameBorder,
height: self.props.height,
key: url,
onLoad: self.props.onLoad.bind(self),
scrolling: self.props.scrolling,
src: self.state.isActive ? url : '',
style: self.props.styles,
width: self.props.width
};
<iframe {...iframeProps} />
This is throwing an error in the console
Refused to display 'https://twitter.com/.... in a frame because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'".
Could anyone please tell me how can I make this work?
The content is prohibited from being displayed within an IFRAME due the Content Security Policy being set. The webserver hosting twitter.com is configured to add a HTTP header to the response object. Specifically they are setting the Content-Security-Policy tag to frame-ancestors 'self'. There is no way you'll be able to embed their pages into a page of your own using IFRAME. There are other techniques that you could use to work around that, but none are as simple as an iframe tag.
W3C Content Security Policy Level 3 - Frame Ancestors
I encountered with this problems recently too and i didn't find any alternative method to solve that.Finally, I came up with idea that the attribute in the iframe,which is "src",can be filled with the origin html content and it works.
// this demo shows the process of getting the html content
// from the link,and then apply it to the attribute "src" in the iframe
$.get(link, function (response){
var html = response;
var html_src = 'data:text/html;charset=utf-8,' + html;
$("#iframeId").attr("src" , html_src);
});
This issue was occurring when trying to upload proof of identity documents to Amazon Pay. The solution was to clear the browser cache and cookies.

Resources