Try   HackMD

【Vue】安全性

回報安全漏洞

如果你發現 Vue 哪邊有安全漏洞,可以 email 給他們。同時 Vue 也推薦都使用最新版本的 Vue 。

最重要的守則: 千萬別使用不安全的模板

最基本的安全守則就是別使用來路不明的模板,這麼做基本上等同於你允許各種 JS 程式在你的專案中執行,如果那些程式碼是在 SSR 期間執行可能還會讓你的伺服器被攻擊。

Vue.createApp({ template: `<div>` + userProvidedString + `</div>` // NEVER DO THIS }).mount('#app')

Vue模板會被編譯成JavaScript,而模板內的表達式將作為渲染過程的一部分被執行。儘管這些表達式在特定的渲染環境中執行,但由於全局執行環境的複雜性,Vue作為一個開發框架,要在性能開銷合理的前提下完全避免潛在的惡意代碼執行是不現實的。避免這類問題最直接的方法是確保你的Vue模板始終是可信的,並且完全由你控制。

Vue 如何保護你

HTML Content

不論是使用模板還是渲染函式,HTML 的內容都會自動轉義( Escape )

<h1>{{ userProvidedString }}</h1>
'<script>alert("hi")</script>'
&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;

如此一來就防止了腳本注入( Script Injection )。這種轉義是使用原生瀏覽器 API(例如 textContent)完成的,因此只有在瀏覽器本身存在漏洞的情況下,才可能存在漏洞。

屬性綁定

和 HTML 一樣,屬性的綁定也會自動轉義

<h1 :title="userProvidedString"> hello </h1>
'" onclick="alert(\'hi\')'
&quot; onclick=&quot;alert('hi')

如此一來就防止了對標題屬性的關閉,以注入新的、任意的 HTML。這種轉義是使用原生瀏覽器 API(例如 setAttribute)完成的,因此只有在瀏覽器本身存在漏洞的情況下,才可能存在漏洞。

潛在的危險

在任何網絡應用程式中,允許未經過濾的、由用戶提供的內容作為 HTML、CSS 或 JavaScript 執行,可能具有潛在的危險性,因此應該在可能的情況下避免使用。

然而,有時候可能會接受一些風險。

例如像 CodePen 和 JSFiddle 這樣的服務允許執行用戶提供的內容,但這是在預期的情況下,並在某種程度上在 iframe 內進行了隔離。在某些情況下,當一個重要功能本質上需要一定程度的漏洞時,就取決於您的團隊權衡該功能的重要性和漏洞可能造成的最壞情況。

HTML Injection

正如前面提到的,Vue 會自動對 HTML 內容進行轉義來防止意外將可執行的 HTML 注入到應用程式中。然而,在確定 HTML 是安全的情況下,就可以明確地渲染 HTML 內容:

模板:

<div v-html="userProvidedHtml"></div>

render function:

h('div', { innerHTML: this.userProvidedHtml })

jsx:

<div innerHTML={this.userProvidedHtml}></div>

使用者提供的 HTML 永遠不能被視為 100% 安全,除非它位於受到沙盒限制的 iframe 中,或者位於應用程式的某個部分,只有撰寫該 HTML 的使用者可能會受到其影響。此外,允許使用者編寫自己的 Vue 模板也帶來類似的危險。

URL Injection

<a :href="userProvidedUrl"> click me </a>

如果 URL 沒有經過「無害化處理」(sanitized) 以防止使用 javascript: 來執行 JavaScript,則可能存在安全問題。有一些像 sanitize-url 這樣的 library 可以幫助解決這個問題。
但請注意,如果你在前端進行 URL 無害化處理,那麼你已經存在安全問題。使用者提供的 URL 應該在儲存到資料庫之前,由後端進行無害化處理。這樣一來,每個連接到你的 API 的客戶端,包括原生移動應用程式,都能避免這個問題。此外,請注意,即使 URL 經過無害化處理,Vue 也無法保證它們會導向安全的目的地。

Style Injection

<a :href="sanitizedUrl" :style="userProvidedStyles" > click me </a>

假設 sanitizedUrl 是一個真實的 URL,而不是 JavaScript。然而,對於 userProvidedStyles,惡意使用者仍然可能提供 CSS 來進行「點擊劫持( clickjacking )」,例如將連結樣式化為一個透明方框,擺放在「登入」按鈕上方。然後,如果 https://user-controlled-website.com/ 被設計得像您應用程式的登入頁面,他們可能剛剛捕獲了使用者的真實登入資訊。

能夠想像,允許使用者提供內容給 <style> 元素將會造成更大的弱點,讓該使用者完全控制如何為整個頁面添加樣式。這就是為什麼 Vue 阻止在模板內部渲染 style 標籤的原因,例如:

<style>{{ userProvidedStyles }}</style>

為了讓您的使用者完全免受點擊劫持的影響,我們建議只在受到沙盒保護的 iframe 內部允許對 CSS 的完全控制。或者在透過樣式綁定提供使用者控制時,我們建議使用物件語法,並且只允許使用者為特定屬性提供值,這些屬性是他們可以安全控制的

<a :href="sanitizedUrl" :style="{ color: userProvidedColor, background: userProvidedBackground }" > click me </a>

JavaScript Injection

我們強烈不建議在 Vue 中渲染 <script> 元素,因為模板和渲染函式不應該具有 Side Effect。然而,這並不是將在運行時評估為 JavaScript 的字串包含的唯一方法。

每個 HTML 元素都有屬性,其值接受 JavaScript 字串,例如 onclick、onfocus 和 onmouseenter。將使用者提供的 JavaScript 綁定到這些事件屬性中任何一個都存在潛在的安全風險,因此應該避免這樣做。

除非在受限制的 iframe 內或是應用程式的某個部分,僅有撰寫該 JavaScript 的使用者會受到影響,否則使用者提供的 JavaScript 永遠無法被視為完全安全。

有時官方會收到關於如何在 Vue 模板中進行跨站腳本攻擊(XSS)的漏洞報告。一般來說,官方不認為這些情況是實際的漏洞,因為一般都是以下這兩種情況:

  1. 開發者明確要求 Vue 將使用者提供的、未經過無害化處理的內容作為 Vue 模板呈現。這本質上是不安全的,Vue 無法知道其來源。
  2. 開發者將 Vue 安裝到整個 HTML 頁面,該頁面包含有伺服器渲染和使用者提供的內容。這本質上與情況 #1 相同,但有時開發者可能在不察覺的情況下這樣做。這可能導致攻擊者提供的 HTML 作為純粹的 HTML 是安全的,但作為 Vue 模板是不安全的。最佳做法是永遠不要將 Vue 安裝到可能包含伺服器渲染和使用者提供內容的節點上。

最佳實踐

一般的原則是,如果允許執行未經無害化處理的使用者提供內容(無論是作為 HTML、JavaScript,甚至是 CSS),都可能使自己容易受到攻擊。這個建議實際上適用於使用 Vue、其他框架,甚至是不使用框架的情況。

推薦熟讀以下資源:

  1. HTML5 安全手冊
  2. OWASP's Cross Site Scripting (XSS) Prevention Cheat Sheet

如果你依賴項目的其中任何一個包括第三方套件或以其他方式影響到所渲染到 DOM 的內容,可以利用你學到的知識來審查他們的原始程式碼,尋找可能存在的危險模式。

Backend Coordination

HTTP 安全性漏洞,例如跨站點請求偽造 (CSRF/XSRF) 和跨站點腳本包含 (XSSI),主要是在後端處理,因此並不是 Vue 的關注重點。然而,與你的後端團隊保持良好的溝通是很重要的,如此以了解如何最佳地與其 API 互動,例如在表單提交時提交 CSRF token。

Server-Side Rendering (SSR)

在使用服務端渲染 (SSR) 時,還存在一些額外的安全考慮,因此請確保遵循官方 SSR 文件 中概述的最佳實踐,以避免產生漏洞。