Recommended method to prevent any content inside iframe from setting cookies - javascript

I get the content to be put inside an iframe from a source I do not trust. For a particular need to be met, I want the content (which might include javascript) to be unable to set cookies at all. What is the recommended method to achieve that?
Edit: I recognize this is similar to this question. I should have mentioned this earlier, but the iframe has a cross-origin source. I want to disable the content inside from setting cookies even on its own source. Does sandboxing achieve that? Thanks.

The short answer:
The HTML5 sandbox attribute prevents an iframe from reading/writing cookies. This is true for both same-origin and cross-origin iframes.
The allow-scripts attribute enables JavaScript but does not interfere with restrictions on cookies.
<iframe sandbox="allow-scripts" src="..."></iframe>
The long answer:
So if you're not fully convinced, this one is for you...
According to the W3C Working Draft (2010) and W3C Recommendation (2014), when the user agent (browser) parses the sandbox attribute, it has to add certain flags, which are then used to put restrictions on the content within the iframe. One of those flags are meant to force the content into a unique origin, and prevent it from reading/writing cookies:
The sandbox attribute, when specified, enables a set of extra restrictions on any content hosted by the iframe.
While the sandbox attribute is specified, the iframe element's nested browsing context must have the flags given in the following list set.
...
...
The sandboxed origin browsing context flag, unless the sandbox attribute's value, when split on spaces, is found to have the allow-same-origin keyword set
This flag forces content into a unique origin, thus preventing it from accessing other content from the same origin.
This flag also prevents script from reading from or writing to the document.cookie IDL attribute, and blocks access to localStorage. [WEBSTORAGE]
When a sandboxed iframe attempts to write a cookie, the following exception is raised:
Uncaught DOMException: Failed to set the 'cookie' property on 'Document': The document is sandboxed and lacks the 'allow-same-origin' flag.
and no cookie is ever written.
Since the sandboxed iframe cannot write cookies at all, it will not be able to set cookies even on its originating site.
(In fact, this would be one of the use-cases for using the allow-same-origin keyword).
The allow-same-origin attribute is intended for two cases.
...
Second, it can be used to embed content from a third-party site, sandboxed to prevent that site from opening popup windows, etc, without preventing the embedded page from communicating back to its originating site, using the database APIs to store data, etc.

Related

Using iframe for rendering user provided html code

I want to embed user provided HTML code in my website. The code will be self-contained, and will contain script and style tags. I am planning to block all network calls from the the provided HTML code by using Content Security Policy headers. The code will only be able to access standard libraries like jquery and other standard resources (the same will be specified in the CSP). I want to restrict any communication between the iframe content and the parent domain.
My plan is to use an <iframe> to embed the content. The user will give an input, and then on clicking a button, an iframe will be rendered with the given input snippet. It will be rendered inline with other content of the page.
I am concerned about the effect of this on the security of my website.
Can I make the origin of the iframe null? Or will I have to host my content on a separate domain so that SOP blocks all the network calls to the parent page?
Will I be able to set up CSP for the iframe separately? If yes, can anyone suggest what all attributes the CSP should have?
Can I take the input html and inject it directly to my iframe from the parent page?
If there are other alternatives which don't use iframe, which are those?
Can I make the origin of the iframe null? Or will I have to host my content on a separate domain so that SOP blocks all the network calls to the parent page?
You can make the origin of the iframe null if you'll use, for instance, a data:-Url. This will prevent cross-origin requests in modern browsers, but Content Security Policy of parent document will be inherited into iframe in all browsers.
In this case some old browsers (Firefox/WinXP) will spread CSP from the iframe to parent document too.
Will I be able to set up CSP for the iframe separately? If yes, can anyone suggest what all attributes the CSP should have?
You are able to set separate CSP for iframe only if it's loaded via network scheme (http:/https:) - it will be created isolated browsing context. If non-network schemes (data:, blob:, etc) iframe will inherit CSP of parent document.
In case of isolated browsing context you can use any "attributes the CSP" what you need for your specific case.
Pay attention to csp=, sandbox= attributes, these can be useful.
Can I take the input html and inject it directly to my iframe from the parent page?
This is contravert your statement: "I want to restrict any communication between the iframe content and the parent domain.".
Therefore all communications are possible via server only.
If there are other alternatives which don't use iframe, which are those?
Isolated browsing contexts can be created via <object>/<embed>, but these are not useful in your case.

Bypassing iframe sandbox?

Someone iframing my website, using
<iframe src="http://example.org" sandbox=""></iframe>
This way, the sandbox attribute prevents my site to use iframe blocker on it. And it can be easily iframed.
Frame buster on my website:
if (window.top !== window.self) window.top.location.replace(window.self.location.href);
Is there a programmatic way to redirect to my site when its being iframed when used with sandbox attribute ?
Iframing can be protected through the X-Frame-Options response header, set either X-Frame-Options value="DENY" or X-Frame-Options value="SAMEORIGIN". Through this response header settings you can protect your website against IFraming or clickjack attack.
Once X-Frame-Options response header is set, browser receives a standard message like "This content cannot be displayed in a frame".
The sandbox attribute is turning off all javascript, amongst other things. This is why your frame buster will not be working, nor any other javascript people have provided.
W3 say of a sandbox:
scripts are disallowed/disabled within the iframe
links to other browsing contexts are disallowed/disabled within the iframe
A test shows that the attribute also disables meta redirects and any standard link which breaks out of the iframe.
With this strictness, I'd be very surprised if a redirect is possible, since that would defeat the point of the sandbox.
The best I can suggest would be to use the noscript tag to display a message to users seeing the page in a sandboxed iframe. You could style that so people can't see your content.
(If it is just one site being a problem, then blocking them with htaccess would probably be a better approach)
I think the best thing you can do is show your own message with a target="top" link. The whole concept of the sandbox attribute is to disallow redirects. There is no way to bypass that and if you ever find one browser makers will probably find a way to stop it. It's clearly their intention.
This is just how the web works. You can't do whatever you want when it comes to browsers.
#SudiptaKumarMaiti's answer of X-Frame-Options works, but is being superseded by Content Security Policy (CSP) Level 2 - specifically the frame-ancestors directive.
To disallow framing completely (similar to X-Frame-Options: DENY), use this HTTP header:
Content-Security-Policy: frame-ancestors 'none';

sessionStorage in iframe

I'm going to have several iframes on my page and I'm going to quite intensively use sessionStorage inside them. What I'm curious about is if I will have separate storages or one shared for all iframes? How do the size limits apply?
If sessionStorage is shared depends on the iframe's page and it's origin, which is the domain part of the URL. If you have a webpage at http://myserver/test.html and it is including http://thatserver/some.html via an iframe, the iframe's page has the domain thatserver. Thus the origin differs and the sessionStorage won't be shared. But if the iframe's page is http://myserver/some.html it has the same origin and therefore will share the same session storage.
Now there is an additional trick: The sandbox attribute for the iframe. If you write <iframe sandbox> without the value allow-same-origin the content of the iframe gets a unique origin. That means it would get a different sessionStorage regardless of the real origin that page has. You can write <iframe sandbox="allow-same-origin"> to sandbox the content AND let the content of the iframe to have the same origin (but only if if does have the real same origin).
Now special notes: sandboxed iframes won't support localStorage per spec. And in webkit-browsers and mozilla firefox an exception will be thrown if the sandboxed iframe content will try to access sessionStorage.
OK, I've made a test myself. At least in Chrome (44) and Firefox (40) the sessionStorage is shared among page and the iframes included if they are of the same domain and do not if they are of different domains.

Why can an iframe change the parent window's URL from a different domain?

I have two domains:
sub1.domain.org contains an iframe with its src pointing to the other: sub2.domain.org
On sub2:
//triggers a cross-domain security error
alert(window.parent.location.href);
//executes just fine on FF, IE, Chrome, and Safari.
window.parent.location.href = new_url;
So it appears I'm allowed to write to the parent window's URL, but I'm not allowed to read it. Is that really the standard? I just need to know why this is working as it does.
I found one answer here: Why can a child redirect a parent frame?
the Same origin policy doesn't apply here, either. By changing the url
in the address bar in your browser window, you're changing the
window.top.location.href property, too. If there were same-origin
restrictions there, the internet would be dead. You're not sending a
request to another location, you're not getting data from a
third-party resource and loading it in your page, you're redirecting
the browser to another location, which closes and clears the DOM.
But this answer prompts other follow up questions.
When we change the parent's URL, aren't we still technically modifying the parent's DOM (even if it closes it) and therefore violating the same-origin policy?
How exactly would the internet be dead if the same origin policy applied here? Surely we can differentiate manually entering URLs in the address bar from changing it via scripts on separate domains.
I understand that this case is not violating the same-origin policy, but I'm still struggling to understand exactly why. Can anyone shed additional insight as to why this is allowed?
It is not a security problem for an iframe to change the URL of a parent window. That just loads a new page into the parent window (thus killing the iframe that was contained in the original parent). There's no security issue there.
The iframe from a different origin is (as you have noticed) not allowed to access the content of a parent as that could be a security issue.
FYI, the reverse is also true. A parent frame can create an iframe and set it's .src to whatever it wants, including other domains, but cannot access the content that loads. The core issue here is that it is not a security problem to display content from other domains, but it can be a security issue to access the actual content from a different origin. So, you're generally allowed to display whatever you want, just not access it.
FYI, the ability to detect whether you are being framed and "bust" out of the frame by resetting the parent window source URL is known as "frame busting" and it is considered a content provider's right to decide whether or not they can be framed or not or who they can be framed by. There are now newer controls that specify whether a site can be framed or not so frame busting is not required in newer browsers.

getting src i.e. url of iframe so that parent page can use it?

Probably, I know the answer already that there is no way by which I can read the DOM Values of Iframe so that Parent can use it.
I spent lot of time researching about it but can not find any way, hence posting it here.
CONSTRAINTS :
Different Domains, No Control over the iframe url. It can be any URL provided by the user.
WHAT I TRIED SO FAR :
I need the value of the url i.e. window.frames['iframename'].location.href but I am getting permission denied as it violates same origin policy.
HTML5 Post message api wont work as it assumes even if they are cross - domain we have control over the iframe page.
easyXSD also assumes the same I suppose.
Is it possible at all?
NOTE : USER Will Change the SRC from Iframe itself. so I use onload method to do something but not able to access location.href
If you have no control over the iframe, then it is not possible since it is a security risk. Notice that you may set the location/url of an iframe/window, but you can not read it (if it is cross domain).
If you had control over the iframe, then workarounds would be possible (using postMessage, workers or whatever).

Categories

Resources