用IFrame內嵌其他網頁是很常見的整合技巧,兩個獨立開發網頁可分別使用,有需要再合體,被內嵌的網頁配合移除頁首頁尾只留內容,看起來天衣無縫,省事又方便。

大家猜猜以下HTML寫法會有什麼結果,網頁上有一小塊出現Google首頁?

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>IFrame Example</title>
  <style>
    iframe { width: 480px; height: 300px; }
  </style>
</head>
<body>
  <iframe src="https://www.google.com.tw" />
</body>
</html>

錯了!

用Chrome檢視上述網頁(Live Demo),IFrame一片空白:

改用IE或Edge開啟得到的訊息多一點:

Edge的錯誤訊息解釋了無法顯示Google首頁的原因:

此內容無法在框架中顯示
這裡應該要有一些內容,但發行者不允許它在框架中顯示。這是為了協助保護您可能在此網站輸入任何資訊的安全性。

解決之道是不要用IFrame內嵌,另開新視窗即可正常檢視。

透過Chrome F12工具我們可以獲得技術面的解釋,有個錯誤訊息:Refused to display 'httqs://www.google.com.tw/' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'. 檢查Response Header,的確可以看到x-frame-options: SAMEORIGIN。這是瀏覽器的安全防護特性之一,限制符合同源政策的網頁才能用IFrame、Frame或Object內嵌這個網頁。

防止網頁被內嵌目的在防止IFrame式Clickjacking攻擊(註:點擊刧持還有其他形式,本文只聚焦透過IFrame攻擊的手法),避免惡意網頁將你的網頁疊加在一般按鈕或連結上方誘使使用者點擊,不知不覺完成開放權限、身份確認… 等操作。隨便調查一下,發現不只Google,像Facebook、Twitter、Yahoo這些大網站也紛紛在HTTP Header加入X-Frame-Options: DENY或SAMEORIGIN。

由X-Frame-Options已被普遍主流網站採用的現象,若用內容農場下標風格,我們可以說:

Google、Facebook都偷偷在HTTP Header加了這個,背後的原因網站開發者們一定要知道… (謎:你夠了哦)

既然大網站都加了防護,想必此一資安風險不容忽視。但IFrame式Clickjacking真有這麼可怕,怎樣可以透過IFrame騙取使用者點擊?實際來個範例比較好懂。假設有一網頁如下,目的在偵測使用者真實身分,唯有正港豬頭才會按鈕自婊。:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <style>
        body {
            background-color: #0094ff;
        }
        button {
            background-color: red;
            color: yellow;
        }
    </style>
</head>
<body>
    <button onclick="alert('我是豬頭')">我是豬頭</button>
</body>
</html>

某駭客黑大發現此網頁未加X-Frame-Options: DENY或SAMEORIGIN防護,心懷不軌搞了個陷阱網頁:先用IFrame內嵌豬頭偵測網頁,利用CSS技巧將IFrame設成position: absolute並調整位置,將「我是豬頭」按鈕蓋在「我是帥哥」按鈕的正上方,再調整CSS opacity透明度使之完全隱形(可參考影片裡的動畫示意)。

使用者只看到「我是帥哥」,按下去一秒變豬頭:

看完示範,應該不難理解為什麼網站要加上X-Frame-Options防護。如果希望整個網站都不准其他網頁內嵌,可以設定網站伺服器在Header中預設加入X-Frame-Options。以IIS為例,可在HTTP回應標頭加入設定:

或直接修改web.config:

  <system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="X-Frame-Options" value="SAMEORIGIN" />
        </customHeaders>
    </httpProtocol>
  </system.webServer>

註:MDN網頁另有Apache、nginx設定回應標頭的方式可供參考。

不過,這個X-Frame-Options Header需要瀏覽器配合才有防護效果,萬一使用者活在世外桃源,使用的版本太舊(對,還在用IE6/IE7的無懷氏之民與葛天氏之民,我就是在說你們),這招就會破功。若要求保險,網頁可再加上:參考

<head>
  <style> body { display : none;} </style>
</head>
<body>
<script>
  if (self == top) {
    var theBody = document.getElementsByTagName('body')[0];
    theBody.style.display = "block"
  } else { 
    top.location = self.location 
  }
</script>
...
</body>

最後補充一點:針對Cross Site Scripting這類攻擊,網頁安全有個新規格-CSP(Content Security Policy),其中定義了 frame-ancestors 可取代 X-Frame-Options,但因為很多瀏覽器還不支援,現階段要防範網頁被內嵌仍是以 X-Frame-Options 為主。

【延伸閱讀】


Comments

# by 小奴

請問黑哥,今天突然被pm 問到,既然iframe 有這樣的危險,為何google map 與youtube 還是可以支援它佔鑲嵌的策略?是否真有安全使用 iframe 的方法?

# by Jeffrey

to 小奴,Iframe允許在任意網頁輕輕鬆鬆嵌入一塊由來源網站100%控制不受干擾的空間,這個便利性很難被其他方法取代。Iframe的主要風險在於使用者可能受欺瞞點擊被內嵌網頁觸發特定操作,因此只要確保被內嵌網頁即使遭誘騙點擊使用者權益不會因此受損,風險即可降低。

# by cheng

請問黑大在 請問您2個問題, 1.此同源政策下 若要在blog.dark/index.html 加入一<iframe src="https://www.google.com.tw"> 解法是在X-Frame-Options 的屬性 ALLOW-FROM 加入 google網址嗎? 2. 若要在https 下開啟iframe 為http的網頁 (企業內部使用) 有什麼解決的方法嗎? 架設一台proxy server嗎?

# by Jeffrey

to cheng, 1. 不對,是被嵌入的一方要加 X-Frame-Options 宣告開放內嵌。以你舉的案例是 Google 得加入 ALLOW-FROM blog.dark (但這應該是謀摳零A代誌) 2. 我想到的解法有二,設定企業內部的瀏覽器允許 https 內嵌 http iframe,或是你說的方法,架 Proxy 將 http 轉成 https。

Post a comment