跳到主要内容

2. X-Frame-Options 头部

2. X-Frame-Options 头部

X-Frame-Options HTTP 头部字段表示一项策略, 指定浏览器是否应在 &lt;frame><iframe> 内渲染所传输的资源. 服务器可以在其 HTTP 响应头部中声明此策略, 以防止点击劫持 (clickjacking) 攻击, 确保其内容不会被嵌入其他站点.

2.1 语法

头部字段名称为:

X-Frame-Options

该头部字段有三个不同值. 它们互斥; 也就是说, 该头部字段必须精确设置为这三个值之一.

DENY

收到带有此头部字段内容的浏览器禁止在任何 frame 中显示该内容.

SAMEORIGIN

收到带有此头部字段内容的浏览器禁止在与内容本身不同源的页面 frame 中显示该内容. 如果浏览器或插件无法可靠判断内容和 frame 的源是否相同, 则必须将其视为 "DENY".

请注意, 当前实现对此条件的解释有所不同. 在某些实现中, 只要求顶级浏览上下文的源与使用 X-Frame-Options 指令的内容源匹配; 在其他实现中, 所有祖先浏览上下文都必须满足此条件. 关于 frame 嵌套以及该头部字段在不同浏览器中行为差异的更多细节, 见第 2.3.2.2 节. 此外, 由此可能产生的潜在安全问题见第 4 节第 2 段.

ALLOW-FROM (followed by a serialized-origin [RFC6454])

收到带有此头部字段内容的浏览器禁止在任何顶级浏览上下文源不同于指定源的页面 frame 中显示该内容. 虽然此头部值可能只有有限支持, 但它正在现代浏览器中被弃用.

请注意, X-Frame-Options 头部字段必须作为 HTTP 头部字段发送, 浏览器会特别忽略 <meta http-equiv> 标签中出现的实例.

2.2 增广巴科斯-诺尔范式 (ABNF)

X-Frame-Options 头部字段值的 RFC 5234 ABNF [RFC5234] 如下:

id-name                = "X-Frame-Options"
X-Frame-Options = "DENY"
/ "SAMEORIGIN"
/ ( "ALLOW-FROM" RWS serialized-origin )

RWS = 1*( SP / HTAB )
; required whitespace

serialized-origin = scheme "://" host [ ":" port ]
; &lt;scheme>, &lt;host>, &lt;port> as per RFC 6454

其中 "serialized-origin" 按 RFC 6454 [RFC6454] 第 6.2 节定义. 产生式 "serialized-origin" 意味着序列化 origin 字符串不得包含任何空白.

2.2.1 X-Frame-Options 示例

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM https://example.com/

2.3 设计问题

2.3.1 启用来自其他域的 HTML 内容

存在若干主要直接向量可启用来自其他域的 HTML 内容, 例如:

  • &lt;frame> elements
  • <iframe> elements
  • <object> elements
  • &lt;applet> elements
  • <embed> elements

除此之外, 其他元素也可能被利用来在父 frame 中执行动作, 从而促成类似点击劫持的攻击, 包括 <script> 标签, <form> 标签和 <button> 标签等. X-Frame-Options 头部字段提供一种机制, 站点运营者可用它表示其页面不应嵌入来自其他域的 frame, 从而防御点击劫持攻击.

2.3.2 浏览器行为和处理

2.3.2.1 违反 X-Frame-Options

当浏览器检测到阻止页面在 frame 中渲染的 X-Frame-Options 头部时, 浏览器必须立即停止渲染该文档.

必须将该页面视为用户已取消加载文档请求. 这类似于用户代理处理 "204 No Content" 响应的方式, 但后者不会导致错误条件.

如果浏览器已经开始下载页面中的图像或其他被包含资源请求, 浏览器应当尽快尝试停止下载这些资源.

2.3.2.2 当前浏览器行为差异

使用 SAMEORIGIN 头部字段时, 浏览器对所需 frame 和浏览上下文检查的解释存在差异. 预期行为是, 仅当 frame 与被嵌入页面同源时, 用户代理才可以在该 frame 中渲染页面.

但是, 浏览器实现各不相同. 某些实现会遍历浏览上下文的整个祖先树, 并要求每个祖先都同源. 其他实现只验证顶级浏览上下文 (窗口) 是否同源.

这意味着, 对于通过多个中间页面被 "framed" 的页面 (即 frame 中的 frame 中的 frame), 成功渲染的页面集合可能比规范意图更严格 (在检查整个祖先链的实现中), 或更宽松 (在只检查顶级 frame 的实现中).

站点运营者应了解这种潜在行为差异, 并在其预期浏览器范围内测试渲染, 以确保符合其反点击劫持策略.

2.3.2.3 ALLOW-FROM 参数的使用设计模式和示例场景

由于不同浏览器支持较弱且实现差异较大, ALLOW-FROM 选项已被弃用. 站点运营者应考虑改用 Content Security Policy 的 frame-ancestors 指令 [CSP2], 它可更好地控制 frame 嵌入策略, 并具有更好的浏览器支持.

2.3.2.4 不缓存 X-Frame-Options 头部

无论 HTTP 响应中或先前缓存的响应中存在何种缓存指令, 浏览器都必须处理每个 HTTP 响应的 X-Frame-Options 头部字段值. 该头部字段在导航时求值, 禁止缓存. 这确保执行最新策略.