跨網站腳本 (XSS) 是安全性弱點,可讓攻擊者將用戶端腳本 (通常是 JavaScript) 放在網頁中。 當其他使用者載入受影響的頁面時,攻擊者的腳本將會執行、讓攻擊者竊取 cookie 和 session、透過 DOM 操作變更網頁的內容,或將瀏覽器重新導向至另一個頁面。 XSS 弱點容易發生在應用程式不驗證、編碼使用者的輸入並將它輸出到頁面時。
除非您遵循下列步驟的其餘部分,否則請勿將不受信任的資料放入您的 HTML 輸入中。 不受信任的資料是指HTML 表單輸入、查詢字串、HTTP 標頭,甚至是從資料庫取得的資料,攻擊者可能控制任何資料,即使它們無法入侵您的應用程式也一樣會受到攻擊。
在 HTML 元素內放置不受信任的資料之前,請確定它是 HTML 編碼。 HTML 編碼會採用 <
之類的字元,並將其變更為安全形式,例如 <
;
將不受信任的資料放入 HTML 屬性之前,請確定它是 HTML 編碼。 HTML 屬性編碼是 HTML 編碼的超集合,並編碼其他字元,例如 "
和 '
。
將不受信任的資料放入 JavaScript 之前,請將資料放在您在執行時間擷取其內容的 HTML 元素中。 如果無法這樣做,請確定資料已編碼為 JavaScript。 JavaScript 編碼會採用 JavaScript 的危險字元,並以十六進位取代它們,例如 <
會編碼為 \u003C
。
將不受信任的資料放入 URL 查詢字串之前,請確定其已編碼 URL。
RazorMVC 中會自動編碼
所有從變數來源的輸出。 每當您使用 @
時, @
它會使用 HTML 屬性編碼規則。
@{
var untrustedInput = "<\"123\">";
}
@untrustedInput
此範例輸出 untrustedInput 變數的內容。 此變數包含 XSS 攻擊中使用的一些字元 <
和 >
。會顯示編碼為:
<"123">
注意
ASP.NET Core MVC 提供 HtmlString
不會在輸出時自動編碼的類別。 這不應該跟不受信任的輸入搭配使用,因為這樣會造成 XSS 弱點。
有時候您可能會想要將值插入 JavaScript 中,在 Views 處理。 做法有二種,插入值的最安全方式是將值放在標記的資料屬性中,並將其擷取到您的 JavaScript 中。 例如:
@{
var untrustedInput = "<script>alert(1)</script>";
}
<div id="injectedData" data-untrustedinput="@untrustedInput" />
//這邊產生html後 @untrustedInput 會變成 <script>alert(1)</script>
<div id="scriptedWrite" />
<div id="scriptedWrite-html5" />
<script>
var injectedData = document.getElementById("injectedData");
// All clients
var clientSideUntrustedInputOldStyle =
injectedData.getAttribute("data-untrustedinput");
// HTML 5 clients only
var clientSideUntrustedInputHtml5 =
injectedData.dataset.untrustedinput;
// 將注入的、不受信任的數據放入 `scriptedWrite` `div` 標籤中。
// 不要在動態生成的數據上使用 `document.write()`,因為它會導致 xss
document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;
// 或者您可以使用 `createElement()` 動態創建 element
// 這次我們使用 `textContent` 來確保數據被正確編碼。
var x = document.createElement("div");
x.textContent = clientSideUntrustedInputHtml5;
document.body.appendChild(x);
// 也可以在元素上使用 `createTextNode` 以確保正確編碼數據。
var y = document.createElement("div");
y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
document.body.appendChild(y);
</script>
注意
請勿在 JavaScript 中串連不受信任的輸入,以建立 DOM 元素,不要在動態生成的數據上使用 document.write()
,因為會導致 XSS。
使用下列其中一種方法來防止程式碼公開至 DOM 型 XSS:createElement()
並使用適當的方法或屬性指派屬性值,例如 node.textContent= 或 node.InnerText= 。document.CreateTextNode()
並將它附加到適當的 DOM 位置。element.SetAttribute()
element[attribute]=
HTML、JavaScript 和 URL 編碼器有兩種方式可供您的程式碼使用,您可以透過 DI
或使用命名空間
中using System.Text.Encodings.Web
public class HomeController : Controller
{
HtmlEncoder _htmlEncoder;
JavaScriptEncoder _javaScriptEncoder;
UrlEncoder _urlEncoder;
public HomeController(HtmlEncoder htmlEncoder,
JavaScriptEncoder javascriptEncoder,
UrlEncoder urlEncoder)
{
_htmlEncoder = htmlEncoder;
_javaScriptEncoder = javascriptEncoder;
_urlEncoder = urlEncoder;
}
}
透過使用編碼器,可以將不信任的資料,轉換成安全的格式。
var html = _htmlEncoder.Encode(exampleString);
var js = _javaScriptEncoder.Encode(exampleString);
var url = _urlEncoder.Encode(exampleString);
使用 UrlEncoder
來編碼
var example = "\"Quoted Value with spaces and &\"";
var encodedValue = _urlEncoder.Encode(example);
編碼之後,encodedValue 會變成 %22Quoted%20Value%20with%20spaces%20and%20%26%22
。 空格、引號、標點符號和其他不安全字元將百分比編碼為其十六進位值,例如空白字元會變成 %20。
Prevent Cross-Site Scripting (XSS) in ASP.NET Core