I’d like to discuss some potential new standards which would let sites allow their content to be embedded in iframes without exposing themselves to clickjacking attacks by the embedding page.
Currently, whenever a site allows itself to be embedded in another site via an iframe (which is the default behavior if you don’t send any headers to prevent this), it risks exposing its users to clickjacking attacks.
In case you’re unfamiliar with how clickjacking works, basically what happens is that an attacker embeds the site it is attacking in an iframe, then tricks the user into clicking something on that page (perhaps by making the iframe transparent and placing it over a button, or by moving the iframe at the last second right before the user clicks something else on the attacker’s page). For more information, you may refer to the OWASP Wiki page on clickjacking.
Currently, most sites protect themselves from this attack by either preventing themselves from being included in iframes entirely (via the
X-Frame-Options header or
frame-ancestors CSP directive) or by asking the user to confirm every action taken inside the frame (Twitter does this by opening a new window asking you to confirm your action when you click the “like” button next to an embedded Tweet).
As these current solutions can be inconvenient for users and developers, I’d like to discuss a possible alternative. Could a new web standard be designed that would allow sites to be embedded in iframes without exposing them to clickjacking attacks?
Here’s what I’m thinking: Imagine a hypothetical new CSP directive
safe-frame-ancestors (or some other, better name) which would direct the user-agent to allow a page to be embedded in an iframe in a way that is resistant to clickjacking attacks. When these pages are embedded in an iframe, the user agent would ignore any user-initiated actions targeted at these frames unless the following conditions are met:
- The iframe is fully opaque
- The iframe is not obscured by any other elements on the page
- The iframe meets some minimum size requirements (perhaps specified by the embedded page via the HTTP header)
- Within the last x seconds (where x = <normal human reaction time>*2 or something like that), the iframe has not done any of the following:
a. Violated any of the previous conditions listed above
b. Changed its size
c. Changed its position on the page (via any means available to scripts on the parent page, including script-initiated scrolling, CSS animations, DOM reflow, etc)
d. Had its src modified by the parent page