聚焦Web前端安全:最新揭祕漏洞防禦方法 | 京東雲技術團隊

在 Web 安全中,服務端一直扮演着十分重要的角色。然而前端的問題也不容小覷,它也會導致信息泄露等諸如此類的問題。在這篇文章中,我們將向讀者介紹如何防範Web前端中的各種漏洞。【萬字長文,請先收藏再閱讀】

首先,我們需要了解安全防禦產品已經爲我們做了哪些工作。其次,我們將探討前端存在哪些漏洞,並提供相應的防範思路。

一、安全防禦產品

安全防禦產品一般有:

傳統互聯網公司的安全防禦體系,類似於一個空氣淨化模型,每個層都有不同的產品,包括網絡層防護、應用層防護、主機層防護、運行時防護、安全開發防護和安全運營防護。外部攻擊流量經過過濾後,到達應用系統的流量相對較爲安全。

對於我們前端而言,最有用的是安全開發防護層中的白盒和黑盒。白盒掃描是對我們的源代碼進行掃描,在上線時會自動檢測問題。黑盒掃描則不考慮程序的結構和代碼細節,對應用程序進行漏洞掃描,每天都有定時任務掃描公網。

在安全方面,我們與集團安全部門進行雙向合作。在集團安全防禦體系已經做了一些工作的基礎上,我們如何針對前端可能存在的漏洞進行防範,是我們研發部門需要思考的問題。

二、漏洞防範

1、安全傳輸

首先,務必使用HTTPS協議,這可以有效防止局域網內的明文抓包。

2、域分離

其次,進行域分離。將一些業務關聯性較小的內容轉移到不相關的域中。如果分離域下出現了XSS漏洞,不會影響業務主域,而且分離域下的XSS漏洞也無法獲得獎勵。如果所有內容都在主域下,一旦主域出現漏洞,主域下的所有子域都會受到破壞。

前端領域常見的漏洞有3種XSS漏洞、CSRF漏洞、界面操作劫持漏洞

3、XSS防禦方案

對於概念,包括名詞定義、攻擊方式、解決方案等估計大家都看過不少,但留下印象總是很模糊,要動手操作一番才能加深印象並能真正理解。

1)XSS 模擬攻擊

先動手實現一個 XSS 的攻擊場景,然後再講解 XSS 的防範手段。看這個代碼:

點擊“write”按鈕後,會在頁面插入一個a鏈接,a鏈接的跳轉地址是文本框的內容。在這裏,通過innerHTML把一段用戶輸入的數據當做HTML寫入到頁面中,這就造成了XSS漏洞。嘗試如下輸入:

首先用一個單引號閉合掉href的第一個單引號,然後閉合掉<a>標籤,然後插入一個img標籤。頁面代碼變成了:

腳本被執行:

所以你明白了吧,XSS跨站腳本攻擊就是注入一段腳本,並且該腳本能夠被執行。其中最常見的XSS Payload就是讀取瀏覽器的Cookie對象。通過盜取Cookie,攻擊者可以直接調用接口,發起“Cookie劫持”攻擊。

爲了防止“Cookie劫持”,集團的統一登錄使用了Cookie的“HttpOnly”和“Secure”標識。

HttpOnly標識表示該Cookie僅在HTTP層面傳輸。一旦設置了HttpOnly標誌,客戶端腳本就無法讀寫該Cookie,從而有效地防禦XSS攻擊獲取Cookie的風險。

Secure標識確保Cookie只在加密的HTTPS連接中傳輸,從而降低了“Cookie劫持”的風險。

因此,建議避免使用localStorage存儲敏感信息,哪怕這些信息進行過加密。因爲localStorage存儲,沒有針對XSS攻擊,做任何防禦機制。一旦出現XSS漏洞,那麼存儲在localStorage裏的數據就極易被獲取到。

2)XSS的危害

讓我們簡單談談XSS的危害。注入的腳本可能會進行JavaScript函數劫持,覆蓋我們代碼中原有的函數,修改js原型鏈上的函數,或在原函數基礎上添加額外行爲。例如,將網絡請求的響應發送到攻擊者的服務器。

JavaScript函數劫持是什麼?它是在目標函數觸發之前重寫某個函數的過程。例如:

let _write = document.write.bind(document);
document.write = function(x) {
    if(typeof(x) == "undefined") { return; }
    _write(x);
}

注入的腳本還可能對用戶進行內存攻擊。如果知道用戶使用的瀏覽器、操作系統,攻擊者就有可以實施一次精準的瀏覽器內存攻擊。通過XSS,可以讀取瀏覽器的UserAgent對象。

alert(navigator.userAgent);

該對象提供了客戶端的信息,如操作系統版本:Mac OS X 10_15_7,瀏覽器版本:Chrome/114.0.0.0

注入的腳本可能強制彈出廣告頁面、刷流量,也可能進行大量的DDoS攻擊,導致網絡擁塞。此外,它還可能控制受害者的機器向其他網站發起攻擊。

如果信貸產品的網頁存在XSS漏洞,黑客可以注入一段腳本,調用查詢借還記錄的接口,並將響應結果發送到自己的服務器。然後,利用用戶的借還記錄等信息,對用戶進行電信詐騙。

第三方統計腳本有機會竊取用戶的敏感信息,如瀏覽歷史、真實IP、地理位置、設備信息,並將其傳送給攻擊者。此外,我們使用的第三方依賴和npm包也有可能竊取用戶信息。在這方面,集團對代碼進行了白盒掃描,已一定程度上規避問題。但最好我們在選擇第三方包時,選擇可信賴的包。

3)XSS 防範方法

XSS 防範方法通常有以下幾種:

①慎防第三方內容:對於流行的統計腳本和第三方依賴,要謹慎使用。

②輸入校驗和輸出編碼:進行輸入校驗,包括長度限制、值類型是否正確以及是否包含特殊字符(如<>)。同時,在輸出時進行相應的編碼,根據輸出的位置選擇適當的編碼方式,如HTML編碼和URL編碼。

③使用HttpOnly屬性:防範XSS攻擊後的"cookie劫持"。

使用Secure屬性,確保Cookie只在加密的HTTPS連接中傳輸,降低"cookie劫持"的風險。

④避免使用localStorage存儲敏感信息。

⑤使用Content-Security-Policy(內容安全策略):可以通過指定只允許加載來自特定域名的腳本,防範XSS攻擊,例如,可以使用以下配置只允許加載來自mjt.jd.com域名的腳本

# 只允許加載來自特定域名的腳本
add_header Content-Security-Policy "script-src mjt.jd.com";

4、CSRF防禦方案

CSRF漏洞是借用用戶的權限做一些事情,注意,是“借用”,而不是“盜取”。XSS漏洞是“盜取”用戶權限,CSRF漏洞是“借用”用戶權限。

1)CSRF 模擬攻擊

我們先動手實現一個 CSRF 攻擊場景,然後再介紹 CSRF 的防範手段。我們要模擬以下場景:用戶先登錄了銀行網站,然後黑客網站誘導用戶訪問和點擊,從而利用用戶的登錄權限,讓用戶給黑客自己轉賬。我們使用 express 啓動一個服務,模擬 CSRF 攻擊。銀行網站的服務啓動在 3001 端口,並提供以下3個接口:

app.use('/', indexRouter);
app.use('/auth', authRouter);
app.use('/transfer', transferRouter);

authRouter:

router.get('/', function(req, res, next) {
  res.cookie('userId', 'ce032b305a9bc1ce0b0dd2a', { expires: new Date(Date.now() + 900000) })
  res.end('ok')
});

/auth 接口在 cookie 中設置了一個名爲 userId 的 cookie,即給用戶授予登錄權限。

transferRouter:

router.get('/', function(req, res, next) {
  const { query } = req;
  const { userId } = req.cookies;
  if(userId){
    res.send({
      status: 'transfer success',
      transfer: query.number
    })
  }else{
    res.send({
      status: 'error',
      transfer: ''
    })
  }
});

/transfer 接口判斷了 cookie,如果存在 cookie,則轉賬成功,否則轉賬失敗。

使用 ejs 提供銀行轉賬頁面:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>
    <%= title %>
  </title>
</head>

<body>
  <h2>
    轉賬
  </h2>
  <script>
    const h2 = document.querySelector('h2');
    h2.addEventListener('click', () => {
      fetch('/transfer?number=15000&to=Bob').then(res => {
        console.log(res.json());
      })
    })
  </script>
</body>

</html>

黑客網站的服務啓動在 3002 端口,並提供一個與銀行網站外觀相同的頁面:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= title %></title>
</head>

<body>

<div class="wrapper" id="container">
  <h2>
    轉賬
  </h2>
  <form action="http://bank.com/transfer" method=GET>
      <input type="hidden" name="number" value="150000" />
      <input type="hidden" name="to" value="Jack" />
  </form>
  <script>
    const h2 = document.querySelector('h2');
    h2.addEventListener('click', () => {
      submitForm();
    })
    function submitForm() {
      document.forms[0].submit(); 
    }
  </script>
</div>
</body>
</html>

由於兩個網站都是在 localhost 域名下,cookie 是根據域名而不是端口進行區分的。因此,我們使用 Whistle 進行域名映射:

# bank.com 映射到 127.0.0.1:3001
bank.com 127.0.0.1:3001

# hack.com 映射到 127.0.0.1:3002
hack.com 127.0.0.1:3002

現在我們開始操作。首先打開瀏覽器,訪問銀行網站 的 /auth獲得授權:

然後通過點擊”轉賬”按鈕發送請求,http://bank.com/transfer?number=15000&to=Bob,進行轉賬操作:

用戶受到郵件或者廣告誘惑進入了 黑客網站,黑客網站首頁有一個“轉賬”按鈕,調銀行的transfer接口 http://bank.com/transfer?number=150000&to=Jack 這個請求放在 <form /> 的 action 中

可以看到請求攜帶了 cookie,併成功轉賬,這樣一次 CSRF 攻擊就完成了。

從上面可以看出,CSRF 攻擊的主要特點是:

①發生在第三方域名(hack.com)

②攻擊者利用 cookie 而不獲取具體的 cookie 值

因此,防範 CSRF 攻擊的關鍵是防止其他人冒充你去執行只有你能執行的敏感操作。

2)CSRF 危害

簡單說,CSRF會導致:個人隱私泄露、機密資料泄露、甚至危及用戶和企業的財產安全。一句話概括CSRF的危害:盜用受害者身份,受害者能做什麼,攻擊者就能以受害者的身份做什麼。

3)CSRF 防範方法

①阻止不同域的訪問:同源檢測

在HTTP請求中檢查Referer或origin字段,確保請求來源是站內地址和站內域名。如果發現Referer或origin地址異常,就可以懷疑遭到了CSRF攻擊。

②使用驗證碼

儘管會降低用戶體驗,但驗證碼是防止CSRF攻擊的最有效手段。

③提交時要求附加本域才能獲取的信息

例如使用一次性token(生成token的因子包括時間戳和用戶ID)來驗證請求的合法性。

④不要允許所有域訪問,使用allow-access-from domain時避免以下方式,即根據前端請求的域來允許訪問:

        String origin = request.getHeader("origin");
        if (StringUtils.isNotEmpty(origin)) {
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
        } else {
            response.setHeader("Access-Control-Allow-Origin", "*");
        }

這種方式是不可取的,應該限制訪問的域。

5、界面操作劫持防禦方案

它是一種基於視覺欺騙的攻擊方式,其核心在於利用標籤的透明屬性。攻擊者會在網頁的可見輸入控件上覆蓋一個不可見的框,從而讓用戶誤以爲自己在操作可見控件,實際上卻是在操作不可見框。

界面操作劫持還包括:點擊劫持、拖放劫持、觸屏劫持

1)常見的攻擊場景

點擊劫持的常見攻擊場景是僞造登錄框。當用戶在僞造的登錄框中輸入用戶名和密碼後,他們以爲自己點擊的是登錄頁面上的登錄按鈕,但實際上他們點擊的是黑客頁面上的“登錄”按鈕,導致密碼被髮送到黑客的服務器上。

拖放劫持利用了拖放操作不受“同源策略”限制的特點,用戶可以把一個域的內容拖放到另一個不同的域。攻擊者結合CSRF漏洞,將iframe中目標網頁的token拖放到攻擊者的頁面中,從而實施攻擊。

觸屏劫持是在手機上進行的一種視覺欺騙攻擊。由於手機屏幕空間有限,手機瀏覽器會隱藏地址欄以節省空間。攻擊者常常利用這一點,當觸發一個權限獲取的提示框時,他們會將提示框的主體背景設爲透明,並覆蓋上僞造的消息提示圖像,只留下權限提示框的確認按鈕。這樣,用戶會誤以爲自己在點擊某個消息的確認,實際上卻是在點擊權限確認。

2)界面操作劫持的防範方法

①Content-Security-Policy (內容安全策略)

# 防禦界面操作劫持
# add_header Content-Security-Policy "frame-ancestors 'self';"; # 只允許網頁在相同被嵌套到框架
# add_header Content-Security-Policy "frame-ancestors 'none';"; # 禁止網頁在任何域名下被嵌套到框架
# add_header Content-Security-Policy "frame-ancestors mkt.shop.jd.com"; # 只允許網頁在某些域名被嵌套到框架

②腳本防禦:破壞frame,防止利用透明層進行操作劫持攻擊

    if (top === self) {
        document.documentElement.style.display = 'block';
    } else {
      top.location = self.location;
    }

③使用iframe嵌入目標網站進行測試,若成功嵌入,則說明可能存在漏洞。

三、培養安全意識

爲了確保代碼的安全性,我們需要培養以下幾點安全意識:

通過培養這些安全意識,我們可以更好地保護我們的代碼和系統,減少安全風險和潛在的攻擊。

作者:京東科技 張朝陽

來源:京東雲開發者社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章