whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
7.98k stars 2.6k forks source link

Allow auto-resize on iframe #555

Open craigfrancis opened 8 years ago

craigfrancis commented 8 years ago

Considering the removal of <iframe seamless> on issue #331.

For me, the main feature of @seamless was the ability for the iframe to resize based on the size of the child document (really just the height), so no scroll bars would appear.

Currently this is "solved" with the use of some very messy JavaScript:

http://stackoverflow.com/search?q=resize+iframe

Which is more difficult cross-origin, which needs postMessage and custom JS running on every single page (both child and parent).

The suggestion of Shadow-DOM is interesting, but I don't believe this provides the same level of protection (and backwards compatibility), as often the child content is put in an iframe to keep it isolated from the current page (i.e. for security reasons).

Typically I put things in an iframe because they could easily be malicious, and I would really like to use a sandbox to block allow-scripts.

zcorpan commented 8 years ago

For cross-origin I suppose the embeddee would need to opt-in somehow (e.g. meta tag), to not expose new information cross-origin.

annevk commented 8 years ago

@craigfrancis you might want to raise this on https://lists.w3.org/Archives/Public/www-style/. In theory this mostly seems like a problem with styling although if this needs to work cross-origin the problem is indeed a little bigger.

zcorpan commented 8 years ago

Some discussion in www-style https://lists.w3.org/Archives/Public/www-style/2016Jan/thread.html#msg236

@annevk @mikewest do you have an opinion about using CORS to allow this for cross-origin? Or would it be better to use CSP or something else?

annevk commented 8 years ago

CORS does not seem great since you only share the height, nothing else. CSP is about adding restrictions. I guess it would be something else. But perhaps we should first see if it gets implemented for the same-origin scenario.

craigfrancis commented 8 years ago

The iframe auto-resize (height) is more of a problem when it's cross origin, as on same origin you can hack this behaviour with:

document.getElementById('iframe').contentWindow.document.body.scrollHeight;

It does fail when the iframes content changes (e.g. navigating to a new page), but there are ways around this:

https://github.com/davidjbradshaw/iframe-resizer/blob/master/src/iframeResizer.js
https://github.com/house9/jquery-iframe-auto-height/blob/master/src/jquery-iframe-auto-height.js
https://raw.githubusercontent.com/cowboy/jquery-resize/v1.1/jquery.ba-resize.js

Ideally we just want to replace all of this browser specific / buggy JavaScript with one line of CSS, the current suggestion being:

iframe { height: max-content; }

This will become even more powerful when cross origin... but as noted, CORS gives too many permissions, CSP is really to restrict access with frame-ancestors, and X-Frame-Options is going away.

So while I'll try to push for this to be implemented, do you have any ideas for handling this securely?

annevk commented 8 years ago

A new header of sorts seems like the way to go. Expose-Height-Cross-Origin: 1 or something lame like that. You could ask https://lists.w3.org/Archives/Public/public-webappsec/ for additional input though I doubt they'd say anything different.

craigfrancis commented 8 years ago

Thanks @annevk, I've posted it at https://lists.w3.org/Archives/Public/public-webappsec/2016Jan/0189.html

mikewest commented 8 years ago

I agree with @annevk; you need something to mitigate the kinds of leakage that this feature would expose. <iframe seamless> was limited to same-origin for this reason. I'm sure we could get away with something less limiting for this subset of seamless's functionality, and I agree that it would be useful.

Expose-Height-Cross-Origin, however you end up spelling it, is probably a reasonable approach. CORS would certainly work, but probably gives away more than you'd like, and CSP isn't the right place for it, as I'd like to keep it negative to the extent possible.

domenic commented 8 years ago

Given that CORS is almost always safe, are we really concerned about "giving too much away"? The only case where a more restrictive header would be useful is if an intranet site wanted to expose its contents' height variation to height-variable iframes, but did not want to expose itself to the wider internet (except through a cross-origin iframe viewport). Is that enough of a use case to justify a new header?

annevk commented 8 years ago

Well, <iframe> is loaded with credentials at which point CORS might not be safe. You might be okay sharing your height, but not your credentialed content. The fetch mode is also "navigate" which thus far has no interaction with CORS and I don't think we want to start introducing that just for exposing the height.

mikewest commented 8 years ago

@domenic: Consider a service like Disqus, which would love to use something like this (and were big advocates for @seamless. They would not be interested in making themselves CORS-same-origin with every site on the net, as that would (for instance) give the sites knowledge of the user's logged-in state.

domenic commented 8 years ago

Got it, credentials are the problem. Too bad there's no way to use CORS headers to automatically prevent credentials from being sent for cross-origin requests.

craigfrancis commented 8 years ago

Just to keep everything together, I've written my notes up at:

https://github.com/craigfrancis/iframe-height

This includes links to the different browsers feature requests.

And a second thought did occur to me... we could look at a new CSS keyword for the resize property, which would be useful to automatically increase its height based on its content - another problem which requires JavaScript to solve.

zcorpan commented 8 years ago

Thank you, excellent work!

The resize property seems like a bad fit for this I think. It's about letting the end user resize an element, but this is not. In principle it could be defined that height: max-content "works" for textarea as well, but that should probably be a separate discussion (new thread on www-style).

craigfrancis commented 8 years ago

Fair point... last week I happened to be replacing some JavaScript that automatically resized a textarea (the JS turned out to be buggy), and I came across a discussion about the 'resize' property for end users (something I don't block, because I think users should be able to change this), and I was wondering if they are kind of exclusive... as in, if the textarea auto resizes, then the user won't need to resize it themselves.

brunoais commented 6 years ago

@zcorpan Any updates on this subject?

sashafirsov commented 6 years ago

@annevk , this question and quite a bit above is in focus of https://github.com/EPA-WG/embed-page POC could be seen at https://www.webcomponents.org/element/EPA-WG/embed-page/demo/demo/index.html

Malvoz commented 6 years ago

For cross-origin I suppose the embeddee would need to opt-in somehow (e.g. meta tag), to not expose new information cross-origin.

Now that we have Feature Policy, I think that's the way to go about that. Similarly, there is a proposal to expose bounds cross-origin.

briansmith commented 5 years ago

Now that we have Feature Policy, I think that's the way to go about that. Similarly, there is a proposal to expose bounds cross-origin.

Content Security Policy (CSP) already has a mechanism, e.g. Content-Security-Policy: frame-ancestors 'self' to control which origins are allowed to frame a document at all. In https://github.com/w3c/webappsec-csp/issues/391 I proposed to extend CSP with a directive to control whether or not the framing document may see just enough information about the iframe's contents to be able to resized it based on its contents. I think it makes more sense to extend CSP than to use feature policy for this, because the CSP frame-ancestors policy already controls a subset of what is needed for this feature (see the issue I filed there).

Note that this issue is marked "needs implementer interest." I encourage people building websites and people building third-party widgets to express their interest in this feature, as it would be a significant security improvement that would help eliminate much use of <script src> for third-party content.

annevk commented 5 years ago

FWIW, https://github.com/w3c/csswg-drafts/issues/1771 is probably the most significant other issue here and there should be some progress there too on a more formal definition of "contents" as I noted in a comment.

annevk commented 5 years ago

How big of a problem is it that navigation of the <iframe> ends up resizing it? It does not seem like a security issue as we already expose navigation in other ways, but it doesn't seem like a great experience either. There might also be some complications here in multi-process architectures if know the embeddee gets to influence the final size.

craigfrancis commented 5 years ago

Starting with consent, we have it both ways - The parent page will opt-in to re-sizing it's iframe via CSS height: max-content; and the child opts-in though a header (where I like @briansmith's suggestion of a CSP frame-ancestors-resizing directive, but also happy with Expose-Height-Cross-Origin: 1).

And for a "first version", I'd still be happy if scrollbars appeared on navigation - as most use cases I can think of don't use navigation.

That said, content can change, and while the browser would ideally change the height automatically, I recognise that it can get into some circular issues.

So how about, the child page calls a method, such as window.parent.resizeMePlease() (when it has finished updating its content), and this asks the browser to do a re-size.

It's not perfect, but the current iframe implementations currently require the child to do a window.parent.postMessage() to tell the parent what size it should be (have fun calculating that), and for the parent to have some JavaScript listening for that message, and applying the new height.

In the case of third party widgets, this means it's much easier to give websites an un-safe <script src="..."> to include (full access to the pages content, and more), rather than a more secure (locked-down) and simple <iframe src="..." style="height: max-content">.

briansmith commented 5 years ago

How big of a problem is it that navigation of the <iframe> ends up resizing it? It does not seem like a security issue as we already expose navigation in other ways, but it doesn't seem like a great experience either.

The kind of use case I'm envisioning would require the use of several controls in concert. On the embedding side, at least:

<iframe
    src="https://my.domain.org.comments.example.com/my-url-slug"
    sandbox="allow-scripts allow-top-navigation-by-user-activation"
    csp="navigate-to 'none'; object-src 'none'">
</iframe>

In particular, I expect the embedder would/should normally disable navigation within the frame using CSP-EE.

On the embedded widget side, they'd need to opt into CSP-EE and also this iframe resizing thing.

[Edited to change the CSP-EE and iframe sandbox directives].

felixfbecker commented 3 years ago

I am a bit confused why the security concern is a blocker for <iframe>, when <object> already does this (at least when embedding an SVG, even cross-origin). <iframe>s are a lot more secure because they have attributes like sandbox and csp, which <object> does not. So currently we are forced to use <object> to embed SVGs in a responsive, accessible, interactive way (<img> doesn't expose contents to screen readers, make links clickable nor text selectable) with no way to disallow scripts in SVG to run. Having iframe resizing would therefor be an improvement to security in my eyes because it stops forcing us to use less secure alternatives.

annevk commented 3 years ago

I thought this proposal was for more than SVG? And it's not clear we'll keep the behavior for <object> the same. There are a number of inconsistencies across browsers there too.

brunoais commented 1 year ago

Almost 2 more years again. Any updates?