Firefox has recently enhanced its implementation of content framing checks, by adding support for Allow-From attribute of X-Frame-Options HTTP response header. This is a good time to revisit the motivation behind framing restrictions and the evolution of security mechanisms in web browsers to control framing.
HTML frames are a standard mechanism for aggregating content from different websites. Originally introduced as framesets in Netscape Navigator 2, they were later generalized to the more usable inline frame notion that remains in widespread use today. On the one hand, frames provide a safer alternative to other mechanisms such as script source inclusion. The same-origin policy can prevent active content from accessing resources on a different website, maintaining a security boundary between the framer and framee. On the other hand, the possibility of seamlessly framing other websites without any way for users to distinguish loca/external content can also lead to confusion and security issues.
The original X-Frame-Options header was introduced as a proprietary extension in Internet Explorer 8 in response to so-called clickjacking or UI-redress attacks. Clickjacking takes advantage of the flexibility of HTML layout to trick users into believing they are interacting with one website, when they are in fact interacting with a different one. The hypothetical example is clicking a seemingly harmless button on a malicious website, but having that click instead delivered to a different button on a banking website, which conveniently inititates a funds transfer from the victim to the attacker. The reason for that surprising otucome: the banking page was in fact present all along, inside a transparent frame “in front of” the malicious site, unbeknownst to the user.
Pulling this off requires the interaction of several features, all of which are seemingly benign in isolation:
- Framing: Embedding the contents of one web site inside another page. In this case a trusted web page.
- Positioning of frames: This allows shifting the framed content around, to better align with the fake UI element visually overlaid behind it.
- Transparency: when third-party content is framed, its transparency can be adjusted from fully opaque to 100% transparent. The latter extreme end of the spectrum leads to a surprising situation: none of the content is visible to the user, but the browser treats this frame as the one in front. User interactions such as clicking inside that region will deliver those inputs to the transparent frame– even though it only has an ethereal presence.
X-Frame-Options tackles the problem by attacking the first condition, controlling which other sites can frame a given page. This is done by having the framee decare its intentions with a new HTTP response header when serving the page. The web browser is responsible for consulting this header when fetching framed content, and applying the stated restrictions to stop content rendering if necessary.
- Check the Referer header in the incoming HTTP request, identifyig the previous website the user is coming from. This sort of works, except that Referer is not guaranteed to be present and there were past vulnerabilities which allowed script or extensions such as Flash to forge that header. (While the user herself can always craft an HTTP request with any Referer, that constitutes a self-attack in this example. The bigger concern is when malicious.com can make a request to widget.com with Referer header set to acme.com, misleading the widget to believe it is being framed from an authorized container.) Given the fragility of the Referer header and its bad reputation as by-design privacy leak across sites, most robust designs shy away from depending on it for security checks.