- From: Dan Kaminsky <dan@doxpara.com>
- Date: Wed, 14 Oct 2015 20:00:30 -0700
- To: public-webappsec@w3.org
- Message-ID: <CAEW7ACnLwf6ztW8DcUMXt7_QR1EDqq1zviy0hW6VCKALkhR-+Q@mail.gmail.com>
Just posted this on the blink-dev list. If you've got an interest in strong viewability / anti-clickjacking you might want to track this thread. ---------- Forwarded message ---------- From: Dan Kaminsky <dan@whiteops.com> Date: Wed, Oct 14, 2015 at 7:58 PM Subject: Fwd: Intent To Implement: UI Security / "IronFrame" To: Dan Kaminsky <dan@doxpara.com> ---------- Forwarded message ---------- From: Dan Kaminsky <dan@whiteops.com> Date: Wed, Oct 14, 2015 at 7:51 PM Subject: Intent To Implement: UI Security / "IronFrame" To: blink-dev@chromium.org *Contact emails* dan@whiteops.com *Spec* http://www.w3.org/TR/UISecurity/ (Code at this time isn't following the spec, rather I'm working on a mechanism to make doing something like this performant. I/White Ops are now W3C now. and we're working with WebAppSec on this directly.) See also http://www.slideshare.net/dakami/i-want-these-bugs-off-my-internet-51423044 and https://www.youtube.com/watch?v=9wx2TnaRSGs *Summary* Quite a few issues for the web platform come down to the fact that embedded content can't be entirely sure what's being presented to the user. For example, navigations to a payment provider (for example, from a shopping cart ot Paypal) occur in lieu of an iframe to Paypal, because the nested iframe could be occluded with an image overlay containing other prices. Same Origin Policy, effective as it is, does serve to prevent embedded content from detecting this sort of manipulation, forcing user hostile designs. A simple fix strategy might involve pixel comparisons between a frame's content and the top view. This unfortunately degrades to the video parsing problem, and is unlikely to ship on any platform. We've been working on Ironframe, an approach based on leveraging the compositing engine to provide the desired security semantics without wrecking performance. Essentially, we force the creation of a GraphicsLayer encapsulating a "protected iframe", determine its position and size relative to the top viewport, and reparent against the root GraphicsLayer. Then, we send events to the documentElement of the raised iframe, describing the visibility of the frame. In concert with ancestorOrigins, this provides sufficient context for a frame to know whether it should allow a transaction to succeed. Is this feature supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)? Yes *Demo* See http://ironframe.whiteops.com. In lieu of building against the linked patch, you may also watch the video at https://youtu.be/c9ed399c3ik . In general, call document.requestVisibility() or set <html requestVisibility=1 style="transform:translateZ(0px)"> in an arbitrarily nested iframe and try to overlay or modify content. A handler on document.documentElement.onerror will give you feedback on how visible the frame thinks it is. *Notes* The goal is for a frame to either know it's visible, or to know that it isn't. (Knowing how visible is a bonus.) As far as security is concerned, it is OK for it to be undefined whether a given case is fully visible or known suppressed (like from being scrolled off page), but of course there are other engineering considerations I'm happy to listen to. Classic timing based clickjacking attacks, i.e. sure it's visible, but it's only been there for a few milliseconds, are catchable by looking at event timestamp and building a delay layer; I'm likely to build this debouncer into some other API. Roughly, we have four kinds of transformations that may affect a nested iframe: Position, Size, Occlusion, Transformation. Position and Size are sacred -- if we're at 50x50 and we have 100x100 pixels, that's all we get. Learning that 50x50x100x100 is a bit tricky though; I'm basically walking the element stack and intersecting bounding rects to figure out what my visible region could be. In general, this approach is surprisingly robust; I think the only thing I had to notably special case was SVG ForeignObject (I would guess nobody in Blink compositing is at all surprised). Given that I'm handling everything from parent elements shrinking on me to clip paths being applied to drop shadows from elements that aren't even on top of me, that's pretty nice. Multiple Ironframes are handled by having one win and the other lose. Eventually you'll be able to unrequestVisibility(). The code is not remotely stable in Debug, because I'm doing layer surgery out of turn. Advice for how to properly handle the compositor and various layer stacks would be greatly appreciated -- it's, uh, complicated in here. The big thing I wanted to do was a) not poll and b) not thrash. This is as much a performance fix as it is a security fix. With performance (mostly) proven, stability is the next goal. Some degree of work on the GraphicsLayer side might be nice. It'd be nice (and probably important) to squash all IronFrame layers into one renderlayer, which can't happen now since iframes can't squash. I also wouldn't hate be able to support drop shadows over Ironframes (at the cost of reducing the number of visible pixels) but that's hard without some sort of layer splitting capacity. It's a goal to make sure this effort does not block process-per-origin work going on elsewhere, meaning the closer I can get to DeprecatedPaintLayer/GraphicsLayer, the better. I'm sorta mining required values from all over the place right now. IronFrame is designed around frame level granularity for viewability, mostly because if you*don't* have a frame (and a cross-origin frame at that) you can't leverage Same Origin Policy to keep anyone from knocking out whatever security you thought you had. It may be the case that from a *design* perspective it's useful to know xywh of an element, even in a foreign frame, relative to the top viewport. There's some goop already supporting this with visibilityOnly as an HTML attribute. I intend to explore this further (courtesy of Alex Russell / Position Observer work). Ultimately, with the input exclusivity that iframes have always had, and the output exclusivity that Ironframe brings, I want to update the address bar to say that a user is interacting with a particular domain. Figuring out that UI is another ball of wax.
Attachments
- text/plain attachment: ironframe2.diff
Received on Thursday, 15 October 2015 03:01:05 UTC