背景
在一些場景下,我們的網站需要通過iframe標簽嵌入第三方廠家的頁面,這時候就得通過iframe標簽去引入需要嵌入網頁的網址了
案例
例如,2月15日是元宵節,為了慶祝元宵,我們需要在主站上線活動頁,這個活動頁剛好是一個第三方網站(歐陽修的一首詞),我們需要把他嵌入到主站中:
主站設計圖如下:
主站實現代碼如下:
<div class="container">
<h3>萬家燈火,共聚團圓 </h3>
<p><em>正月十五元宵節</em></p>
<div class="ad">
<iframe src="https://www.zzcyes.com/yuanxiao/ci.html"></iframe>
</div>
</div>
問題
把代碼提交之后,打開我們的主站,效果卻變成了這樣:
查看控制台,有以下報錯信息:
Refused to display 'https://www.zzcyes.com/' in a frame because it set 'X-Frame-Options' to 'deny'.
控制台說在ifame嵌入的第三方網站拒絕了我們的訪問,因為它把X-Frame-Options
設置成了deny
。
X-Frame-Options
MDN對它的解釋如下:
The X-Frame-Options HTTP 響應頭是用來給瀏覽器 指示允許一個頁面 可否在
<frame>
,<iframe>
,<embed>
或者<object>
中展現的標記。站點可以通過確保網站沒有被嵌入到別人的站點里面,從而避免 clickjacking 攻擊。
換一句話說,如果設置為 deny
,不光在別人的網站 frame 嵌入時會無法加載,在同域名頁面中同樣會無法加載。另一方面,如果設置為sameorigin
,那么頁面就可以在同域名頁面的frame
中嵌套。
deny
表示該頁面不允許在 frame 中展示,即便是在相同域名的頁面中嵌套也不允許。sameorigin
表示該頁面可以在相同域名頁面的 frame 中展示。allow-from _uri_
表示該頁面可以在指定來源的 frame 中展示。
解決方案
知道X-Frame-Options
的含義后,那么我們只需將X-Frame-Options
的值設為sameorigin
或allow-from uri
即可。由於第三方頁面是通過nginx部署的,因此,我們需要配置 nginx 發送 X-Frame-Options 響應頭,把sameorigin
或allow-from uri
添加到 "http","server"或者 "location"的配置中(保存好配置后記得重啟nginx -s reload
)
X-Frame-Options:sameorigin
如果主站和嵌入的第三方網頁在同一個域中,可以把add_header X-Frame-Options sameorigin
這一行,添加到nginx配置中:
server {
#listen 80;
listen 443 ssl; // 主站是https協議
server_name www.zzcyes.com;
add_header X-Frame-Options sameorigin;
// 省略其它配置
...
}
X-Frame-Options:allow-from uri
如果主站和嵌入的第三方網頁不在同一個域中,可以把add_header X-Frame-Options "ALLOW-FROM url"
這一行,添加到nginx配置中去。這里的url是指你主站的url,也就是嵌入iframe的網頁地址,不是iframe上訪問的網址。
假設主站網址為https://www.zzcyes.com
,配置如下:add_header X-Frame-Options "ALLOW-FROM https://www.zzcyes.com"
若有多個主站需要嵌入第三方網頁,則需要用逗號分隔多個主站的網址:
add_header X-Frame-Options "ALLOW-FROM https://www.zzcyes.com,http://www.zzcyes.com"
server {
#listen 80;
listen 443 ssl; // 主站是https協議
server_name www.zzcyes.com;
add_header X-Frame-Options "ALLOW-FROM https://www.zzcyes.com";
// 多個用逗號分隔
#add_header X-Frame-Options "ALLOW-FROM https://www.zzcyes.com,http://www.zzcyes.com";
...
}
注意:當按以上配置允許iframe展示的網站時,控制台打印如下錯誤:
Invalid 'X-Frame-Options' header encountered when loading 'https://www.zzcyes.com/': 'ALLOW-FROM https://www.zzcyes.com'is not a recognized directive. The header will be ignored.
控制台打印說我設置的標頭X-Frame-Options不生效,我反復檢查了下nginx的配置,確實沒有問題。於是想了下會不會瀏覽器版本的,是不是不支持allow-from
這個語法,果然,在mdn瀏覽器兼容性的表上查到了,果然不支持(chrome瀏覽器)allow-from
這個語法,那么這種方案(在chrome瀏覽器上)就行不通了
Content-Security-Policy
如果主站和嵌入的第三方網頁不在同一個域中,通過設置X-Frame-options的值為allow-from url
這個方法,顯然在大部分瀏覽器上都不支持(IE和火狐除外)。同樣在mdn對X-Frame-Options描述下有這么一段話:
The added security is only provided if the user accessing the document is using a browser supporting X-Frame-Options. Content-Security-Policy HTTP 頭中的 frame-ancestors 指令會替代這個非標准的 header。CSP 的 frame-ancestors 會在 Gecko 4.0 中支持,但是並不會被所有瀏覽器支持。然而 X-Frame-Options 是個已廣泛支持的非官方標准,可以和 CSP 結合使用。
這里引出了Content-Security-Policy
,具體用法請到MDN查閱。