Review: Same-origin policy
First, let's clarify that the behavior observed here (the iframe does not render) is much stricter than the default same-origin policy. If you already understand that, skip down to "What's actually happening," below.
To review, the same-origin policy prevents scripts from having programmatic access to the contents of cross-origin resources. Consider how the same-origin policy applies to various types of resources:
- Images: An
<img> tag will show a cross-origin image to a user visually, but it will not allow a script to read the image content when loaded into a
toDataURL will fail if the canvas contains any cross-origin images)
- Scripts: Cross-origin scripts will run when referenced in a
<script> element, but the page can only run the script, not read its contents.
- Iframe: Like images, the contents of a framed cross-origin page appear visually to the user, but scripts in the outer framing page are not allowed access to the framed page's contents.
The same-origin policy applies to iframes for the same reason it applies to all other types of resources: the web page being framed (or the image being displayed, or the resource being accessed via Ajax) is fetched using credentials from the resource's own origin (e.g., the HTTP request to fetch a resource from
google.com includes my browser's cookies set for
google.com). The page that issued the request should not be given read-access to a resource fetched with credentials from a different origin.
What's actually happening: X-Frame-Options
However, the behavior you see here is stricter than the same-origin policy: the framed page is not shown at all. The cross-origin server that hosts the (would-be) framed page requests this blocking behavior by sending an
X-Frame-Options response header, which specifies how the page is allowed to be framed.
- DENY The page cannot be displayed in a frame, regardless of the site attempting to do so.
- SAMEORIGIN The page can only be displayed in a frame on the same origin as the page itself.
- ALLOW-FROM uri The page can only be displayed in a frame on the specified origin.
Here, the site sends
X-Frame-Options: SAMEORIGIN, which means the site can only be framed by pages with the same origin as the framed page.
From a security standpoint, this is done to prevent clickjacking (also called a "UI redress" attack). In a clickjacking attack, the page displays a click-activated component of another site inside an
<iframe> and tricks the user into clicking it (usually by layering the the target component on top of an apparently-clickable feature of the framing site).
For a trivial example, a site might position a transparent
http://security.stackexchange.com so that the "log out" link in the framed site was directly over top of a "Click here to claim your free money" button. When viewing the framing page, the user attempts to claim the free money, and suddenly finds himself logged out of Stack Exchange. When
http://security.stackexchange.com sends an
X-Frame-Options: SAMEORIGIN header, the malicious cross-origin page gets only an empty
<iframe> instead; the user doesn't unwittingly click a log-out link because no content from the framed site made it onto the rendered page.
OWASP has a page detailing defenses against clickjacking.