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

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.

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;"

NextJS Content Security Policy (CSP)

I am currently making a Content Security Policy (CSP) for a production application made with Next.js. While I have found trustworthy documentation for implementing a CSP with the framework, there are a couple of concerns that I want to make sure are addressed correctly.
Issue #1: I have read that security policies set in HTTP headers are preferable. However, I cannot find a way to pass a 'nonce' attribute for inline styles in production using this approach. https://nextjs.org/docs/advanced-features/security-headers
Issue #2: I've seen other examples where developers inject their CSP in the custom document("./pages/_document.js"). I am hesitant to use this approach because I hear meta-tag CSPs are easily bypassable. https://github.com/vercel/next.js/tree/canary/examples/with-strict-csp
My Questions:
Is there a way to use a 'nonce' with header configuration in "next.config.js"? If so, how?
Is specifying "unsafe-inline" for styles in production a security issue at all if Next.js automatically sanitizes user input? I should also mention that I sanitize all mongo database queries in my APIs as well.
Is there something about the meta tag approach described in Issue #2 that makes it as secure as the HTTP header approach?
What approach do you recommend I take to make my CSP as strong as possible for my web app?
All the best,
-Sam
NextJS has 2 pre-rendering mode: Static Site Generation(SSG) and Server-Side Rendering(SSR). The first one has no way to update nonce='value' in the HTML code, but when SSG you can pass a 'nonce' attribute for inline styles and scripts using ./pages/_document.tsx.
See an example for CSP header and meta tag CSP example.
Re Quersions:
I think using a next.config.js is possible, for example next-safe package adds a nextSafe() function into this file to set a lot of headers:
.
const nextSafe = require('next-safe')
const isDev = process.env.NODE_ENV !== 'production'
module.exports = {
async headers () {
return [
{
source: '/:path*',
headers: nextSafe({ isDev }),
},
]
},
}
To set 'nonce' into CSP header you can craft your own function in this way. To set 'nonce' attribute into styles you can use _document.tsx renderer.
Specifying 'unsafe-inline' for styles in production is not a security issue. For example https://accounts.google.com page allows inline styles (it even does not have style-src/default-src directives but it carefully controls scripts).
Setting CSP in HTTP headers is preferable but this does not mean that CSP in meta tag is easily bypassable. Just CSP in meta tag has some restrictions and if you do not use features that have been restricted you can safely use meta tag to delivery CSP.
You can strengthen the protection indefinitely, spending a lot of time and resources. Just follow the main principle "protection should not be more expensive than the protected object".

Electron: Security concern regarding inline styles in an iframe

Question: I'm trying to load an external script (let's say from example.com) in the Electron app. The External script loads everything in an iframe and it's using inline styles, which renders the widget without any styles due to Electron CSP. I don't want to use unsafe-inline CSP on the whole application, I need it just on this iframe which comes from "example.com".
Error which I get: Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self'"
For resolving this I am thinking to add this code block in my electron app -
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
if(details.url.includes("example.com") && details.url.includes(".html")) {
callback({
responseHeaders: Object.assign({
"Content-Security-Policy": [ "default-src 'self';style-src 'unsafe-inline' https://*.example.com https://example.com" ]
}, details.responseHeaders)});
}
This code block will ensure to have 'unsafe-inline' CSP only in the iframes of "abc.com". But, I want to check that can this code block still cause any kind of security threat to my app?
Does your iframe contain any user entered data? If not then this is fine. If it does then you will need to find another way to check they have not entered any inline styles

Geolocation denied for HTML embedded site - anchor tag feature policy

The iframe with allow="geolocation" works great.
But what if I want to load a link which calls getCurrentPosition() from a html anchor tag?
Example :
In iframe, I'll use
<iframe src="https://siteWhichCallsGetGeolocation.com" allow='geolocation'></iframe>
I have a use case where a html embed link like
Click here to get geolocation
is embedded in a parent site.
The parent site loads the child link inside it's own iframe
It is to be noted that The parent site's iframe has the allow="geolocation" attribute .
In this case the request is silently denied with error
errorCode :1
errorMessage: "Geolocation has been disabled in this document by
permissions policy."
The feature policy document point to iframe but what about anchor tag embeds?
I understand that I can use a iframe instead of anchor tag embed but the parent site only allows anchor tag's.
PS - This is my first question here. Please assist.
Note :
I also tried a random shot by including allow="geolocation" for anchor tag, but it doesn't work.
This seems to work on Safari (which I'm assuming is because Safari hasn't yet implemented feature policy for cross origin site requests)
Edit 1 :
I tried my use case in jsfiddle and notice that all scripts i give (iframe or anchor tag) are loaded inside jsfiddle's iframe
<iframe name="result" allow="midi; geolocation; microphone; camera; display-capture; encrypted-media;" sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-popups allow-top-navigation-by-user-activation allow-downloads" allowfullscreen="" allowpaymentrequest="" frameborder="0" src=""> </iframe>
If i load my iframe inside this, it works perfectly !(perfectly balanced, as all things should be...)
But if I load my anchor tag inside this, i get the error. As per granty's answer
the jsfiddle's iframe with allow='geolocation' should set jsfiddle site's feature policy that all scripts loaded inside that iframe can access geolocation right ? Why does my iframe inside jsfiddle's iframe work but anchor tag doesnt ?
Note - I have no control over the top level site. I only code the scripts for https://siteWhichCallsGetGeolocation.com
SOLUTION (if you have control over top document's feature policy or control over any intermediate <iframe> which have geolocation permission) (derived from granty's answer)
I tried the suggested solution by changing the jsfiddle's iframe attribute via inspect element to
<iframe name="result" allow="midi; geolocation https://siteWhichCallsGetGeolocation.com ; microphone; camera; display-capture; encrypted-media;" sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-popups allow-top-navigation-by-user-activation allow-downloads" allowfullscreen="" allowpaymentrequest="" frameborder="0"></iframe>
To highlight, I added my site next to geolocation in allowlist like
allow="midi; geolocation https://siteWhichCallsGetGeolocation.com ;
and then loaded my anchor tag.
When the getCurrentPosition() was triggered from script loaded from https://siteWhichCallsGetGeolocation.com, I got the browser prompt to Allow/Deny location sharing. I allowed and got the coordinates!
Wow! If only it could be as simple as editing the top level document's feature/permissions policy via inspect element.
But alas,I have no control over the top level document's feature policy. At least I understood what's going on under the hood.
Briefly, you have to publish
Feature-Policy: geolocation https://siteWhichCallsGetGeolocation.com;
HTTP response header, when the server sends page into browser.
TL; DR or What's going on under the hood
The allow="geolocation" attribute is used to set Feature Policy (now it's renamed to Permissions Policy) inside iframe.
You use the geolocation directive with an emplty list of origins, therefore a default policy geolocation 'src' is applied. This means that inside iframe is allowed Geolocation API for scripts loaded from the same location as iframe - https://siteWhichCallsGetGeolocation.com.
Pls note that for allow="geolocation" default policy is 'src'(the origin from iframe's src=). But if you use directive Feature-Policy: geolocation;, the default policy for empty list is 'self'.
To set Feature Policy in the main page (top level document) is intended the Feature-Policy header. If it didn't set, the default policy geolocation 'self' is applied. This forbids using Geolocation API for scripts loaded from https://siteWhichCallsGetGeolocation.com origin.
Therefore use
Feature-Policy: geolocation https://siteWhichCallsGetGeolocation.com;
or
Feature-Policy: geolocation 'self' https://siteWhichCallsGetGeolocation.com;
if your own page uses geolocation too.
Ref EDIT 1
Jsfiddle's <iframe allow="geolocation;" means <iframe allow="geolocation 'src';". It means only scripts loaded from the same origin(Url) as jsfiddle iframe can access Geolocation API. Therefore it does not allow your anchor tag from the https://siteWhichCallsGetGeolocation.com origin.
BUT passing permissions of parent page into nested iframe perform a tricky way. If some browsing context has some permission, it can grant it to any nested contexts independantly of its origin (if it creates this context by self).
So jsfiddle's iframe has permission for geolocation. Inside jsfiddle's iframe is placed your nested iframe having allow='geolocation 'src'.
Jsfiddle's iframe delegate its permission for geolocation to your iframe, of course the allowed origin is changed when permission passing into another iframe.
Yes, scripts loaded from third-party Urls can create iframe too, but they can't grant geolocation permission, because they do not have it - since loaded from origins for which geolocation is not allowed.
the jsfiddle's iframe with allow='geolocation' should set jsfiddle site's feature policy that all scripts loaded inside that iframe can access geolocation right?
Not "loaded inside that iframe", but loaded from the same Url, as that iframe.
Otherwise, what's the point of specifying a list of allowed origins like allow="camera 'self' https://www.youtube.com", if any not listed script can have access to your camera.
It's a bad practice to use hidden default, therefore you was mislead. Instead of:
<iframe allow="midi; geolocation; microphone; camera; display-capture; encrypted-media;"
should be:
<iframe allow="midi 'src'; geolocation 'src'; microphone 'src'; camera 'src';
display-capture 'src'; encrypted-media 'src';"

mailto href inside frame not working when Content Security Policy

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.

Resources