Cross-Frame Scripting (Missing Cross-Frame Scripting Protection) 缺少跨框架腳本保護

跨框架腳本(XFS)漏洞使攻擊者能夠在惡意頁面的 HTMLiframe 標記內加載易受攻擊的應用程序。攻擊者可以使用此漏洞設計點擊劫持攻擊,以實施釣魚式攻擊、框架探查攻擊、社會工程攻擊或跨站點請求偽造攻擊。其他網站會在他的iframe中調用我的網站內容,來截取他人的點擊事件或者竊取他人敏感信息。

網站弱點掃描如果有列到Cross-Frame Scripting這一項,並提到「此 URL 可被嵌入在測試 網頁的框架中,惡意攻擊者可於框架外建立釣魚頁面,進而騙取使用者做出意想之外的行為,建議與 AP 廠商確認與修補。」那就表示你的網站可以被其他網頁以iframe或其他網頁frame的方式假裝是你的網站,進行騙取民眾的帳號、密碼之類的個資資料。

可以參考這篇文章的處理方式,依你的伺服器類型來處理

https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Headers/X-Frame-Options

設定 Apache 請加入以下指令到網站組態設定檔:
Header always append X-Frame-Options SAMEORIGIN

ServerRoot "/etc/httpd"
DocumentRoot "/srv/www/htdocs"
Alias /download/ "/home/cht_s/"

DirectoryIndex index.html


X-Frame-Options

這是為了防止IFrame式Clickjacking攻擊,Browser設定的一種規範

規範

資安議題

防止釣魚網站透過iframe來籤入自己的網站。並且在iframe上面埋一個隱形的DIV,欺騙使用者。 這是瀏覽器的安全防護特性之一,限制符合同源政策的網頁才能用IFrame、Frame或Object內嵌這個網頁。

防止網頁被內嵌目的在防止IFrame式Clickjacking攻擊(註:點擊刧持還有其他形式,本文只聚焦透過IFrame攻擊的手法),

避免惡意網頁將你的網頁疊加在一般按鈕或連結上方誘使使用者點擊,不知不覺完成開放權限、身份確認… 等操作。

隨便調查一下,發現不只Google,像Facebook、Twitter、Yahoo這些大網站也紛紛在HTTP Header加入X-Frame-Options: DENY或SAMEORIGIN。

釣魚網站的做法

<!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透明度使之完全隱形(可參考影片裡的動畫示意)。

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

如何檢查

chrome

  1. F12打開Network
  2. 點選「Doc」尋找該網址的主要Document
  3. 點了後會出現詳細清單,選取「Header」
  4. 尋找「X-Frame-Options」

瀏覽器相容性

如何防止

如果希望整個網站都不准其他網頁內嵌,可以設定網站伺服器在Header中預設加入X-Frame-Options

[ISS]

  • Header設定

以IIS為例,可在HTTP回應標頭加入設定,或者使用web.config

  • HTTP 

  • web.config

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

[Apache]

請加入以下指令到網站組態設定檔:

Header always append X-Frame-Options SAMEORIGIN

[nginx]

請加入以下指令到 http, server 或 location 組態設定檔:

add_header X-Frame-Options SAMEORIGIN;

[HAProxy]

請加入以下指令到 frontend, listen, 或 backend 組態設定檔:

rspadd X-Frame-Options:\ SAMEORIGIN

X-Frame-Options

參數說明:

  • DENY

    表示文件無論如何都不能被嵌入到 frame 中,即使是自家網站也不行。

  • SAMEORIGIN

    唯有當符合同源政策下,才能被嵌入到 frame 中。

  • ALLOW-FROM uri

    唯有列表許可的 URI 才能嵌入到 frame 中。

各瀏覽器處理結果

X-Frame-Options Header需要瀏覽器配合才有防護效果

瀏覽器相容性

chrome

chrome

IE

IE8以後才有 IE

Firefox

當載入一個 X-Frame-Options 不允許的網站到 iframe 中, Firefox 會顯示about:blank 的空白頁面,甚至某些狀況還會顯示錯誤訊息。

參考

新的規則: CSP , frame-ancestors

針對Cross Site Scripting這類攻擊,網頁安全有個新規格-CSP(Content Security Policy),

其中定義了 frame-ancestors 可取代 X-Frame-Options,但因為很多瀏覽器還不支援,現階段要防範網頁被內嵌仍是以 X-Frame-Options 為主。

https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives#frame-ancestors

延伸閱讀



檢測報告中的修復方法還說明了開發人員還必須使用客戶端 frame busting JavaScript 作為對 XFS 的保護,故又進行了相關的查詢,其實就是使用JavaScript來檢測頁面是否是當前打開頁面的最外層,如果不是,將最外層的地址換成本頁面的地址,實現方法很簡單,如下:

if (top != "http://10.107.34.210/") {top.location.replace("http://10.107.34.210/"); }

Create a test page containing an HTML iframe tag whose src attribute is set to ~FullURL~. Successful framing of the target page indicates that the application is susceptibile to XFS.

創建一個包含 HTML iframe 標記的測試頁面,該標記的 src 屬性設置為 ~FullURL~。目標頁面的成功成幀表明該應用程序易受 XFS 影響。

POST /pscgi.cgi HTTP/1.1<br>Referer: http://10.107.34.210/pscgi.cgi?PAGE=LoginForm<br>Host: 10.107.34.210<br>Accept: */*<br>Accept-Language: en-US,en;q=0.5<br>Accept-Encoding: gzip, deflate<br>Content-Type: application/x-www-form-urlencoded<br>Content-Length: 176<br>Origin: http://10.107.34.210<br>Pragma: no-cache<br>User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0<br>Connection: Keep-Alive<br>X-WIPP: AscVersion=21.1.0.137<br>X-Scan-Memo: ScriptEngine="Gecko";Category="Crawl";SID="FDEC625DA80F7D213E88EB999EE590DF";PSID="AA3A652A17BB9A2C496AE1E127F7FE8C";SessionType="Crawl";CrawlType="ScriptFrameInclude";AttackType="None";OriginatingEngineID="00000000-0000-0000-0000-000000000000";tht="21";<br>X-RequestManager-Memo: stid="9";stmi="0";sc="1";rid="d7a99a58";<br>X-Request-Memo: rid="52d6115c";sc="1";thid="40";<br>Cookie: CustomCookie=WebInspect178410ZX4BBFA2A7A33648B88064C060E2F1903BY0736<br><br>PAGE=LoginPost&FROM=LoginForm&__J__=0%2c0%2c0&__K__=0&__IV1__=-1&__IV2__=-1&__SUB_N__=0&__SUB_2_N__=0&__OPT_W__=0&__OPT_T__=0&__OPT_S__=-1&__PS_PORT__=10102&PSKEY0_0=&PSKEY1_0=


HTTP/1.1 200 OK<br>Date: Mon, 03 Oct 2022 10:05:33 GMT<br>Server: Apache<br>X-Frame-Options: SAMEORIGIN<br>X-XSS-Protection: 1; mode=block<br>Keep-Alive: timeout=5, max=97<br>Connection: Keep-Alive<br>Content-Type: text/html; charset=UTF-8<br>Content-Length: 4055<br><br><br><HTML><HEAD><meta http-equiv="Content-Security-Policy:frame-ancestors" content="self"> <meta http-equiv="X-Content-Type-Options" content="nosniff"> <meta http-equiv="x-xss-protection" content="1"> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache, must-revalidate"> <meta http-equiv="expires" content="0"><meta http-equiv="Content-Type" content="text/html"; charset="utf-8" /><link rel="stylesheet" href="site_top-menu.css" type="text/css" /><script type="text/javascript" src="./menu_theme/JSCookMenu.js"></script><link rel="stylesheet" href="./menu_theme/theme.css" type="text/css" /><script type="text/javascript" src="./menu_theme/theme.js"></script><script type="text/javascript" src="./skinnytip.js"></script><link rel="stylesheet" type="text/css" media="all" href="calendar/skins/aqua/theme.css" title="Aqua" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/skins/tiger/theme.css" title="Tiger" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-blue.css" title="winter" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-blue2.css" title="blue" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-brown.css" title="summer" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-green.css" title="green" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-win2k-1.css" title="win2k-1" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-win2k-2.css" title="win2k-2" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-win2k-cold-1.css" title="win2k-cold-1" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-win2k-cold-2.css" title="win2k-cold-2" /><link rel="alternate stylesheet" type="text/css" media="all" href="calendar/calendar-system.css" title="system" /><script type="text/javascript" src="calendar/calendar.js"></script><script type="text/javascript" src="calendar/lang/calendar-big5-utf8.js"></script><script type="text/javascript" src="calendar/click_calendar.js"></script><TITLE></TITLE><br></HEAD><br><BODY onLoad='callLoadFunction()' ><DIV id='container'><DIV class='gap'><script type='text/javascript' language='javascript'>var can_submit = true;</script><br><FORM METHOD=POST NAME='form1' ACTION='pscgi.cgi' onSubmit='return canSubmit()'><br><INPUT TYPE=hidden NAME="PAGE" VALUE=""><INPUT TYPE=hidden NAME="FROM" VALUE="LoginPost"><INPUT TYPE=hidden NAME="__J__" VALUE="0,0,0"><INPUT TYPE=hidden NAME="__K__" VALUE="0"><INPUT TYPE=hidden NAME="__IV1__" VALUE="-1"><INPUT TYPE=hidden NAME="__IV2__" VALUE="-1"><INPUT TYPE=hidden NAME="__SUB_N__" VALUE="0"><INPUT TYPE=hidden NAME="__SUB_2_N__" VALUE="0"><INPUT TYPE=hidden NAME="__OPT_W__" VALUE="0"><INPUT TYPE=hidden NAME="__OPT_T__" VALUE="0"><INPUT TYPE=hidden NAME="__OPT_S__" VALUE="-1"><INPUT TYPE=hidden NAME="__PS_PORT__" VALUE="10102"><script type='text/javascript' language='javascript'>var form_emt = document.form1.elements;function setOptParameter(who, type){form_emt['__OPT_W__'].value = who;form_emt['__OPT_T__'].value = type;can_submit = true;}</script><br><TABLE width='100%' rules='none' cellpadding='0' cellspacing='0'><TD id='banner' width='750px'></TD><TD id='repeat-banner'></TD></TABLE><DIV id='links'><DIV class='side-banner'><DIV class='side-banner-title'></DIV></DIV></DIV><DIV id='content'><DIV class='message'><DIV class='error-message-div'>登入認證失敗, 登入失敗[10102]</DIV></DIV><DIV class='div-button'><INPUT TYPE='button' NAME='GoBack' class='button' value='退回' onClick='history.back()' ></DIV><script type='text/javascript' language='javascript'>function callLoadFunction(){}</script><br><script type='text/javascript' language='javascript'>function canSubmit(){return can_submit;}</script><br></FORM><br></DIV><DIV id='footer'><DIV class='footer-description'></DIV></DIV></DIV></DIV></BODY></HTML><br>


Description:


A Cross-Frame Scripting (XFS) vulnerability can allow an attacker to load the vulnerable application inside an HTML iframe tag on a malicious page. The attacker could use this weakness to devise a Clickjacking attack to conduct phishing, frame sniffing, social engineering or Cross-Site Request Forgery attacks.

跨幀腳本 (XFS) 漏洞可允許攻擊者在惡意頁面的 HTML iframe 標記內加載易受攻擊的應用程序。攻擊者可以利用這個弱點設計點擊劫持攻擊來進行網絡釣魚、幀嗅探、社會工程或跨站點請求偽造攻擊。


Clickjacking (點擊劫持)


The goal of a Clickjacking attack is to deceive the victim (user) into interacting with UI elements of the attacker’s choice on the target web site without their knowledge and then executing privileged functionality on the victim’s behalf. To achieve this goal, the attacker must exploit the XFS vulnerability to load the attack target inside an iframe tag, hide it using Cascading Style Sheets (CSS) and overlay the phishing content on the malicious page. By placing the UI elements on the phishing page so they overlap with those on the page targeted in the attack, the attacker can ensure that the victim must interact with the UI elements on the target page not visible to the victim.

Clickjacking 攻擊的目標是欺騙受害者(用戶)在攻擊者不知情的情況下與攻擊者在目標網站上選擇的 UI 元素進行交互,然後代表受害者執行特權功能。為了實現這一目標,攻擊者必須利用 XFS 漏洞將攻擊目標加載到 iframe 標籤內,使用級聯樣式表 (CSS) 將其隱藏,並將網絡釣魚內容覆蓋在惡意頁面上。通過將 UI 元素放置在網絡釣魚頁面上,使其與攻擊目標頁面上的元素重疊,攻擊者可以確保受害者必須與受害者不可見的目標頁面上的 UI 元素進行交互。

WebInspect has detected a response containing one or more forms that accept user input but is missing XFS protection.

WebInspect 檢測到包含一個或多個接受用戶輸入但缺少 XFS 保護的表單的響應。

A Cross-Frame Scripting weakness could allow an attacker to embed the vulnerable application inside an iframe. Exploitation of this weakness could result in:


1. Hijacking of user events such as keystrokes

2. Theft of sensitive information

3. Execution of privileged functionality through combination with Cross-Site Request Forgery attacks


跨框架腳本漏洞可能允許攻擊者將易受攻擊的應用程序嵌入到 iframe 中。利用這一弱點可能會導致:
 1. 劫持擊鍵等用戶事件
 2. 竊取敏感信息
 3. 結合跨站請求偽造攻擊執行特權功能

Recommendation:


The Content Security Policy (CSP) frame-ancestors directive obsoletes the X-Frame-Options header. Both provide for a policy-based mitigation technique against cross-frame scripting vulnerabilities. The difference is that while the X-Frame-Options technique only checks against the top-level document’s location, the CSP frame-ancestors header checks for conformity from all ancestors.



If both CSP frame-ancestors and X-Frame-Options headers are present and supported, the CSP directive will prevail. WebInspect recommends using both CSP frame-ancestors and X-Frame-Options headers as CSP is not supported by Internet Explorer and many older versions of other browsers.

內容安全策略 (CSP) frame-ancestors 指令廢棄了 X-Frame-Options 標頭。兩者都提供了針對跨框架腳本漏洞的基於策略的緩解技術。不同之處在於,雖然 X-Frame-Options 技術僅檢查頂級文檔的位置,但 CSP frame-ancestors 標頭檢查所有祖先的一致性。

In addition, developers must also use client-side frame busting JavaScript as a protection against XFS. This will enable users of older browsers that do not support the X-Frame-Options header to also be protected from Clickjacking attacks.

此外,開發人員還必須使用客戶端框架破壞 JavaScript 作為對 XFS 的保護。這將使不支持 X-Frame-Options 標頭的舊瀏覽器的用戶也可以免受 Clickjacking 攻擊。

X-Frame-Options

Developers can use this header to instruct the browser about appropriate actions to perform if their site is included inside an iframe.

如果他們的網站包含在 iframe 中,開發人員可以使用此標頭指示瀏覽器執行適當的操作。

Developers must set the X-Frame-Options header to one of the following permitted values:

開發人員必須將 X-Frame-Options 標頭設置為以下允許值之一:DENY、SAMEORIGIN、ALLOW-FROM origin、Content-Security-Policy: frame-ancestors。


DENY

Deny all attempts to frame the page

SAMEORIGIN

The page can be framed by another page only if it belongs to the same origin as the page being framed

ALLOW-FROM origin

Developers can specify a list of trusted origins in the origin attribute. Only pages on origin are permitted to load this page inside an iframe

Content-Security-Policy: frame-ancestors

Developers can use the CSP header with the frame-ancestors directive, which replaces the X-Frame-Options header, to instruct the browser about appropriate actions to perform if their site is included inside an iframe. Developers can set the frame-ancestors attribute to one of the following permitted values:

開發人員可以將 CSP 標頭與 frame-ancestors 指令一起使用,該指令替換 X-Frame-Options 標頭,以指示瀏覽器在其站點包含在 iframe 中時執行適當的操作。開發人員可以將 frame-ancestors 屬性設置為以下允許值之一:

‘none’

Equivalent to “DENY” - deny all attempts to frame the page


‘self’

Equivalent to “SAMEORIGIN” - the page can be framed by another page only if it belongs to the same origin as the page being framed


<host-source>

Equivalent to “ALLOW-FROM” - developers can specify a list of trusted origins which maybe host name or IP address or URL scheme. Only pages on this list of trusted origin are permitted to load this page inside an iframe


<scheme-source>

Developers can also specify a schema such as http: or https: that can frame the page.


留言

這個網誌中的熱門文章

10.29 Slow HTTP Denial of Service Attack (Slowloris)

在CentOS 8 Stream安裝NTP Client與設定時區

Update Pattern of TrendMicro AntiVirus Software - ServerProtect