iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
Vue.js

Vue & GraphQL 探險之旅:30天,從新手村到魔王之巔系列 第 17

[Day17] 星塵護盾:防禦 XSS 的第一道防線 – Vue 的文本轉義機制

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231015/201411112e22fBk2HF.png

Day16 的文章中,我們透過 query string 與 props 來傳遞「keyword」,進而實現搜尋功能。同時,為了確保安全性,我們對使用者的輸入進行了嚴格的過濾:只允許英文、數字、底線、連字符號和空白,且長度限制在 100 個字符內。

這樣的限制看似簡單,但背後的意義卻十分重大。假如這些限制不存在,系統可能會面臨哪些安全威脅呢?

前端資安領域中,開發者或許會經常聽到「XSS攻擊」。但究竟什麼是 XSS?又有哪些策略能夠有效地預防這種威脅?

解開這些疑惑後,我們將深入探索 Vue 框架如何提供協助,預先為開發者提供了一系列的安全防護措施。

https://ithelp.ithome.com.tw/upload/images/20231015/20141111b0mxKsyhlV.jpg


基於 Query String 的簡單 XSS 攻擊示範

在這個示範中,我們會展示如何透過讀取 Query String 並直接插入到 HTML 中,來執行一個簡單的 XSS 攻擊。

以下是一個簡單的範例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XSS Demo</title>
</head>
<body>
<div id="content"></div>

<script>
  // 取得 query string
  const queryString = window.location.search.substring(1);

  // 將 query string decode 直接放入 HTML
  document.getElementById('content').innerHTML = decodeURIComponent(queryString);
</script>
</body>
</html>

注意:該代碼僅供示範之用。在實際應用中,這種方式可能導致安全漏洞,所以強烈建議避免使用。

XSS 攻擊示範

當我們輸入 /?HelloWorld 訪問頁面時,會看到 HelloWorld
https://ithelp.ithome.com.tw/upload/images/20231015/20141111Xv2z6u39os.png
看起來毫無威脅?

但如果更改為使用 /?<img src="x" onerror="alert('XSS')"> 訪問,則會觸發並執行程式碼中未定義的 script!
https://ithelp.ithome.com.tw/upload/images/20231015/20141111Tjn4P8GiqL.png

原理解析

由於不正當的資料處理和不完整的防護機制常成為攻擊者的利用點,多數瀏覽器和框架為防範 XSS 攻擊已經提供了一系列的安全措施。
(也因此,其實範例的程式碼還是刻意寫出帶有漏洞的程式碼,只為了說明概念。)

那究竟是哪些程式碼片段造成 XSS 攻擊生效的呢?

  1. decodeURIComponent
    許多現代瀏覽器會自動轉義某些字符以提高安全性。特別在 URL 或 query string 中,字符如 <> 會被轉換為它們的 URL 編碼形式,例如 %3C%3E
    如果沒有使用 decodeURIComponent,而是直接把 queryString assign 給 innerHTML,這個攻擊甚至不會被觸發。

  2. innerHTML
    現代的教學文獻都會建議初學者使用 .textContent 或其他更安全的方法來處理用戶輸入,也會標註 innerHTML 的不安全性。

整體來說,該程式碼在讀取 query string 之後,先使用解碼並插入 HTML。
當輸入 <img src="x" onerror="alert('XSS')"> 時,它會導致瀏覽器解析這段代碼,並當圖像加載失敗時,觸發 onerror 事件, XSS 攻擊生效,彈出警告框 "XSS"。


XSS 簡介與基本防範策略

跨站腳本攻擊(Cross-Site Scripting,縮寫:XSS)是一種在網頁應用程式中的安全漏洞,它允許攻擊者將惡意腳本注入到其他使用者的網頁中。當其他使用者瀏覽這些帶有惡意腳本的網頁時,這些腳本將在他們的瀏覽器中運行。這樣,攻擊者可以繞過同源策略,從而訪問其他使用者的資料或在受害者的瀏覽器中執行任意代碼。

XSS 的不良影響

那麼如果 XSS 發生了,會導致什麼不良影響呢?

  • 數據竊取:攻擊者可以利用 XSS 攻擊獲取使用者的 Cookie 或其他敏感資料。
  • 身份冒充:透過竊取使用者的 session,攻擊者可以冒充該使用者,進行不法行為。
  • 網站毀損:攻擊者可以修改網站的內容或外觀,影響品牌和用戶信任。

預防策略

在資訊安全的世界裡,挑戰是永無止境的,因為每次技術進步,新的威脅和漏洞也隨之出現。

正如程式是由人類編寫,完美無瑕的程式碼幾乎是一個遙不可及的理想。不過,這並不代表我們不能努力追求更高的安全標準和更完善的保護措施。

以下是一些基礎防範 XSS 的策略:

  1. 輸入驗證:確保所有使用者輸入的資料都進行驗證和過濾,避免接受包含惡意腳本的輸入。
  2. 使用 Content Security Policy (CSP):內容安全策略 (CSP) 可以用來限制瀏覽器只能執行來自特定來源的腳本,阻止攻擊者注入惡意腳本。
  3. 避免使用 eval():不要使用 eval() 或相似的 JavaScript 函數,因為這會執行動態代碼,很容易被濫用。
  4. 正確使用模板引擎:許多前端和後端模板引擎提供了自動的輸出轉義功能。確保了解和正確使用這些功能。
  5. 輸出編碼:在網頁中輸出資料時,例如將資料插入 HTML、JavaScript 或其他上下文之前,應進行適當的編碼或轉義,防止 HTML 或 JavaScript 代碼被執行。
  6. 使用 HTTP-only Cookies:這可以防止腳本訪問敏感的 Cookie。
  7. 定期審核和更新:定期檢查您的網站和第三方插件,確保都使用最新版本,並修復已知的安全漏洞。

Vue 提供的安全機制

Vue.js,作為當前最受歡迎的前端框架之一,自然也對安全問題給予了高度的關注。
開發者如果正確使用 Vue,可以有效地避免多種常見的前端安全問題,特別是 XSS 攻擊。

Vue 提供了哪些安全機制

  1. 自動文本轉義:Vue 預設會將所有的數據轉義,所以在使用文本插值 (Interpolation),如 {{ message }})時,Vue 會自動將 message 中的任何特殊字符轉義。
  2. 禁用 HTML 插值:Vue 並不允許在文本插值中使用 HTML 代碼 (除非使用 v-html 指令,但使用時需要特別小心)。
  3. 組件隔離:Vue 的組件化架構也對安全有所幫助。每個組件都運行在隔離的範疇中,這減少了潛在的安全風險。
  4. 內置的 Content Security Policy (CSP) 兼容性:Vue 提供了與 CSP 規則兼容的版本,這有助於進一步加固應用的安全性。

為什麼我們需要文本轉義?

文本轉義主要是為了防止 XSS 攻擊。在 XSS 攻擊中,攻擊者會試圖注入惡意腳本到網頁中。如果網站不小心將這些腳本呈現給使用者,那麼當使用者訪問該頁面時,這些惡意腳本就會被執行。

一個留言的例子
假設網站有架設留言區供使用者交流,而一個攻擊者在評論中輸入了 <script>alert('Hacked!');</script>。如果這個輸入直接被渲染到頁面上,那麼每當有人查看該評論時,都會看到一個彈窗。實際上,攻擊者可以執行更加惡意的操作,如竊取 cookie 或其他敏感信息。

因此,我們需要文本轉義來確保所有的輸入都被視為純文本,而不是執行代碼。

Vue 的文本轉義機制是如何運作的?

自動轉義插值內容

當我們在 Vue 模板中使用 {{ message }} 進行資料綁定時,Vue 會使用一個內部的轉義函數將 message 中的特殊字符(如 <, >, & 等)轉換為它們的 HTML 實體形式,例如 <, >&

這意味著即使 message 中包含惡意代碼或腳本,它也只會被視為純文本並被正確地呈現,而不會被執行。

綁定屬性值的安全性

當使用 v-bind 或簡寫為 : 進行屬性值綁定時,Vue 會確保內容作為純文本解析,而非 HTML 或腳本。

指令功能的限制

例如,v-forv-if 這些指令都經過設計,確保它們不會執行任意的 JavaScript 代碼。

謹慎使用 v-html

如果開發者真的需要渲染原始的 HTML,例如渲染 Rich Editor 產生的內容,Vue 提供了 v-html 指令。
但使用上必須非常謹慎,因為直接使用 v-html 意味著插入真實的 HTML,且不進行轉義,如此一來就有可能導致 XSS 攻擊,特別是當渲染的內容來自使用者輸入時,開發者需要自行對渲染內容進行轉義或過濾。


實際範例

Day16 文章中的搜尋功能舉例

只需在 src/views/BlogSearchView.vue 的 template 區塊中添加以下這行程式碼:

<div v-html="keyword" />

當使用者在搜尋框中輸入 <img src="x" onerror="alert('XSS')">,則XSS攻擊將被成功觸發。
https://ithelp.ithome.com.tw/upload/images/20231015/20141111KrneTFdqZL.png

這是因為我們直接利用 v-html 渲染了未經過任何過濾的 props.keyword,進而造成了這樣的安全風險。


Recap

今天,我們一同探索了 XSS 攻擊的基礎知識,相信讀者對於資安風險的意識會更有警覺性。

還是老話一句,理解這些潛在的風險及其背後的原理十分重要。只有當我們明白哪些做法是不好的,我們才能撰寫更安全的程式。

我們還談到 Vue 提供了哪些安全機制,讓開發者可以專注在應用的核心功能,省下不少擔憂資安的心力。Vue 的文本轉義機制,是我們對抗邪惡 XSS 攻擊的第一道防線。最後,透過實際的例子和操作,希望讀者能更加熟悉這個機制。

我們在 Day16 觀察到的問題還有一個:Header 和 Sidebar 中都存在著重複的搜尋功能邏輯。
為了解決這個問題,明天我們將會深入介紹 Vue Composition API 中的 Composable,這將幫助我們更有效率地重構和管理那些重複的程式碼。敬請期待!


場外加映:Prototype pollution

Prototype pollution 是一種攻擊手法,攻擊者藉由修改原型鏈來影響所有的物件。如果不當地處理使用者輸入,這個攻擊手法可能會在 JavaScript 應用中發生。

以下是一個基本的範例,展示如何透過 query string 實施 prototype pollution:

const url = require('url');
const querystring = require('querystring');

function merge(target, source) {
    for (let key in source) {
        if (typeof source[key] === 'object') {
            if (!target[key]) target[key] = {};
            merge(target[key], source[key]);
        } else {
            target[key] = source[key];
        }
    }
}

function processQueryString(queryStr) {
    const params = querystring.parse(queryStr);

    let obj = {};
    merge(obj, params);
    return obj;
}

const userInput = 'prototype.polluted=true';
const processedData = processQueryString(userInput);
console.log(({}).polluted); // outputs "true"

這個範例中,我們模擬了從 URL 的 query string 取得的輸入,並透過 merge 函數將其合併到目標物件上。由於我們沒有做任何檢查或過濾,攻擊者可以傳入如 'prototype.polluted=true' 的值,從而修改原型鏈,這導致所有的物件都帶有了 polluted 屬性。

為避免這種攻擊,你應該避免使用遞迴合併或直接將使用者輸入賦值給物件,特別是當使用者輸入的鍵或值可以動態更改時。


上一篇
[Day16] 實戰演練:在 Vue 中運用 GraphQL 的條件查詢,實現多面貌的搜尋和排序功能
下一篇
[Day18] 魔法重構:使用 Vue 3 Composition API 與 Composable 實現模組化程式碼管理
系列文
Vue & GraphQL 探險之旅:30天,從新手村到魔王之巔31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言