- From: Michal Zalewski <lcamtuf@dione.cc>
- Date: Thu, 25 Sep 2008 19:24:04 +0200 (CEST)
Hi folks, I am posting here on the advice of Ian Hickson; I'm new to the list, so please forgive me if any of this brings up long-dismissed concepts; hopefully not. For a couple of months now, along with a number of my colleagues at Google, we were investigating a security problem that we feel is very difficult or impossible to avoid on application side, and might be best addressed on HTML or HTTP level in contemporary browsers. These problems had recently gained some mainstream attention, and so we hoped to discuss potential solutions, and perhaps gain some traction for long-term fixes. Problem definition: a malicious page in domain A may create an IFRAME pointing to an application in domain B, to which the user is currently authenticated with cookies. The top-level page may then cover portions of the IFRAME with other visual elements to seamlessly hide everything but a single UI button in domain B, such as "delete all items", "click to add Bob as a friend", etc. It may then provide own, misleading UI that implies that the button serves a different purpose and is a part of site A, inviting the user to click it. Although the examples above are naive, this is clearly a problem for a good number of modern, complex web applications. Practical, real-world examples of such "UI redress" attacks were demonstrated in the past, and recently resurfaced on an OWASP conference (under the name of "clickjacking"); some references include: * http://www.thespanner.co.uk/2008/02/11/csrf-chat/ * https://www.owasp.org/index.php/OWASP_NYC_AppSec_2008_Conference * http://lists.immunitysec.com/pipermail/dailydave/2008-September/005356.html We feel that current web browser designs provide no adequate tools for web site owners to protect their applications against such attacks. The two workarounds often employed right now are: 1) Using Javascript hacks to detect that window.top != window to inhibit rendering, or override window.top.location. These mechanisms work only if Javascript is enabled, however, and are not guaranteed to be reliable or future-safe. If the check is carried on every UI click, performance penalties apply, too. Not to mention, the extra complexity is just counterintuitive and weird. 2) Requiring non-trivial reauthentication (captcha, password reentry) on all UI actions with any potential for abuse. Although this is acceptable for certain critical operations, doing so every time a person adds Bob as a friend on a social networking site, or deletes a single mail in a webmail system, is very impractical. Other quick fixes are easy to come up with, but in general prove problematic in many usage scenarios. Based on our internal conversations, we have a number of proposals for approaches to how to address the issue, along with their pros and cons outlined. All these could be tweaked, combined, etc.; none of them seems quite ideal. Proposed fixes: 1) Create a HTTP-level (or HTTP-EQUIV) mechanism along the lines of "X-I-Do-Not-Want-To-Be-Framed-Across-Domains: yes" that permits a web page to inhibit frame rendering in potentially dangerous situations. Pros: - Super-simple Cons: - "Opt-in", i.e. currently vulnerable sites remain vulnerable unless action is taken - Can't be used for cases where IFRAME content mixing has a legitimate purpose (for example, cross-domain gadgets, certain types of mashups) - Adds yet another security measure (along with cross-domain XHR, MSIE8 XSS filters, MSIE P3P cookie behavior, Mozilla security policies) that needs to be employed correctly everywhere to work - which is very unlikely to consistently happen in practice - Along with the aforementioned security features, threatens to result in HTTP header or HTML HTTP-EQUIV size bloat that some sites may care about. 2) Add a document-level mechanism to make "if nested <show this> else <show that>" conditionals possible without Javascript. One proposal is to do this on the level of CSS (by using either the media-dependency features of CSS or special classes); another is to introduce new HTML tags. This would make it possible for pages to defend themselves even in environments where Javascript is disabled or limited. Pros: - Lightweight - Far more fine-grained than proposal #1 (though still not perfect) Cons: - "Opt-in" (sites remain vulnerable unless action is taken) - Might seem like an odd abuse of CSS / HTML 3) Add an on-by-default mechanism that prevents UI actions to be taken when a document tries to obstruct portions of a non-same-origin frame. By carefully designing the mechanism, we can prevent legitimate uses (such as dynamic menus that overlap with advertisements, gadgets, etc) from being affected, yet achieve a high reliability in stopping attacks. [ I like this one the most myself, but we were far from reaching any consensus. ] Algorithm description: A) Permit frames to be nested arbitrarily by default. B) If anything is to be drawn partly or fully on top of a region occupied by a nested IFRAME (in a callback from the renderer), look up the parent of the obstructing visual element drawn (that is, the party in charge of element's positioning). Always allow the element to be drawn, but if the parent is not same-origin with the target of an obstructed IFRAME, set a flag to disable UI input to that obstructed IFRAME (i.e., have the browser sink all UI events from now on). We may also gray out the disabled IFRAME (and maybe allow CSS to customize this behavior for specific IFRAMES). C) Treat a case where top-left corner of the IFRAME is drawn out of a visible area (CSS negative margins, etc) as a special case of being obstructed by the owner of a current rendering rectangle (another IFRAME or window.top) and carry out the same comparison. D) Once the obstruction is removed (say, a menu folded back), initiate a security timer (500-1000 ms or so) to eventually re-enable UI input to the IFRAME. E) Cases where a non-same-origin IFRAME is newly spawned by Javascript, or same-origin -> non-same-origin location updates takes place, should be treated as special cases of the IFRAME being uncloaked, and result in UI event lockout until a security timer expires. F) Regardless of the aforementioned mechanism, do not permit an IFRAME target that is not same-origin with its parent document to invoke .focus() or to reposition content using URL anchors. This is to make sure that the top-left corner of the page as seen by the user always displays the top-left corner of the actual page. A potential optimization for D) and E), to minimize any potential impact where attacks are unlikely to succeed, is to: - Permit a short window of opportunity (0.5 second, perhaps) following initial page load, as well as possibly mouse clicks, during which cross-domain IFRAMEs may be revealed with no timer penalty, based on the assumption that immediate and involuntary UI actions are unlikely to follow. ...or alternatively: - Disable UI events or initiate timeouts only if cursor is within a certain radius of the uncloaked non-same-origin frame, based on the same assumption. Pros: - Works by default Cons: - Moderately complex and kludgy - In implementations, would require callbacks from the renderer to detect obstruction, as opposed to making decisions without this knowledge - Further investigation is needed to verify that this doesn't break the legitimate and common practice of some sites 4) Enforce a click-to-work mechanism (resembling the Eolas patent workaround) for all cross-domain IFRAMEs. Pros: - Works by default - Very simple Cons: - May be cumbersome for users - May not play well with gadgets, advertisements, etc. 5) Rework everything we know about HTML / browser security models to make it possible for domains and pages to specify very specific opt-in / opt-out policies for all types of linking, referencing, such that countering UI redress attacks would be just one of the cases controlled by this mechanism. Pros: - Awesome in theory, security-wise Cons: - Not really going to happen any time soon Cheers, /mz
Received on Thursday, 25 September 2008 10:24:04 UTC