ASP.NET Core Blazor 互動式伺服器端轉譯的威脅風險降低指引
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
本文說明如何降低互動式伺服器端 Blazor 的安全性威脅。
應用程式採用具狀態資料處理模型,其中伺服器和用戶端會維護長期關聯性。 持續性狀態是由可以跨越可能長時間存留連線的線路所維護。
當使用者瀏覽網站時,伺服器會在伺服器的記憶體中建立線路。 線路會向瀏覽器指出要轉譯和回應事件的內容,例如當使用者在 UI 中選取按鈕時。 為了執行這些動作,線路會在使用者的瀏覽器和伺服器上的 .NET 方法中叫用 JavaScript 函式。 這種雙向 JavaScript 型互動稱為 JavaScript Interop (JS Interop)。
由於 JS Interop 會透過網際網路發生,而用戶端會使用遠端瀏覽器,因此應用程式會共用大部分的 Web 應用程式安全性考量。 本主題描述伺服器端 Blazor 應用程式的常見威脅,並提供著重於網際網路面向應用程式的威脅風險降低指引。
在受限制的環境中,例如公司網路或內部網路,有一些風險降低指引:
- 不適用於受限制的環境中。
- 不值得實作的成本,因為受限制的環境中的安全性風險很低。
已啟用 WebSocket 壓縮的互動式伺服器元件
壓縮可能會讓應用程式暴露在連線 TLS 加密的旁路攻擊下,例如 CRIME 和 BREACH 攻擊。 這些類型的攻擊需要網路攻擊者:
- 強制瀏覽器透過跨網站表單張貼或將網站嵌入至另一個網站的 iframe 內,對易受攻擊的網站發出具有網路攻擊者控制承載的要求。
- 觀察透過網路壓縮和加密回應的長度。
若要讓應用程式易受攻擊,必須在回應中反映來自網路攻擊者的承載,例如,將路徑或查詢字串寫入回應中。 使用回應的長度,網路攻擊者可以「猜測」回應上的任何資訊,略過連線加密。
一般而言,Blazor 應用程式可以使用適當的安全性措施,透過 WebSocket 連線啟用壓縮:
當應用程式從受網路攻擊者影響的要求取得內容 (例如路徑或查詢字串) ,並將其複製至頁面的 HTML,或使其成為回應一部分時,該應用程式可能易受攻擊。
Blazor 會自動套用下列安全性措施:
設定壓縮時,Blazor 會自動封鎖將應用程式內嵌至 iframe,這會封鎖來自伺服器的初始 (未壓縮) 回應轉譯,並防止 WebSocket 連線開始。
將應用程式內嵌至 iframe 的限制可能會放寬。 不過,如果嵌入文件透過跨網站指令碼弱點遭到入侵,放寬限制會使應用程式面臨攻擊,因為這為網路攻擊者提供了執行攻擊的方法。
通常若要發生此類型攻擊,應用程式必須重複重現回應中的內容,讓攻擊者可以猜測回應。 假設 Blazor 的轉譯方式 (轉譯一次,然後只針對已變更的元素產生差異內容),網路攻擊者就很難完成此動作。 不過,這對網路攻擊者來說並非不可能,因此必須小心避免將敏感性資訊與網路攻擊者可操作的外部資訊一起轉譯。 以下提供一些這類範例:
在頁面上轉譯個人識別資訊 (PII),同時轉譯其他使用者新增的資料庫資料。
將 PII 資訊轉譯至頁面,同時透過伺服器上的 JS Interop 或本機單一資料庫服務,轉譯來自其他使用者的資料。
一般而言,我們建議您避免轉譯包含敏感性資訊的元件,以及可轉譯來自不受信任來源的資料作為相同轉譯批次一部分的元件。 不受信任的來源包括路由參數、查詢字串、來自 JS Interop 的資料,以及第三方使用者可以控制的任何其他資料來源 (資料庫、外部服務)。
共用狀態
伺服器端 Blazor 應用程式位於伺服器記憶體中,且多個應用程式工作階段會裝載在相同的處理程序內。 針對每個應用程式工作階段,Blazor 會啟動具有其本身相依性插入容器範圍的線路,因此每個 Blazor 工作階段的範圍服務都是唯一的。
警告
除非非常小心,否則不建議使用單一資料庫服務在相同伺服器共用狀態上的應用程式,因為這可能會造成安全性弱點,例如跨線路洩漏使用者狀態。
如果應用程式特別針對它所設計,您可以在 Blazor 應用程式中使用具狀態單一資料庫服務。 例如,使用單一資料庫記憶體快取是可接受的,因為記憶體快取需要索引鍵才能存取指定的項目。 假設使用者無法控制與快取搭配使用的快取索引鍵,則儲存在快取中的狀態不會跨線路洩漏。
如需狀態管理的一般指導,請參閱 ASP.NET Core Blazor 狀態管理。
Razor 元件中的 IHttpContextAccessor
/HttpContext
IHttpContextAccessor 必須避免使用互動式轉譯,因為沒有有效的 HttpContext
可用。
IHttpContextAccessor 可用於伺服器上靜態轉譯的元件。 不過,建議您盡可能避免。
只能在一般工作的靜態轉譯根元件中將 HttpContext 用作 級聯參數,例如檢查和修改 App
元件 (Components/App.razor
) 中的標頭或其他屬性。 用於互動式轉譯的值一律是 null
。
[CascadingParameter]
public HttpContext? HttpContext { get; set; }
針對互動式元件中所需 HttpContext 的案例,建議您透過伺服器的持續元件狀態來流動資料。 如需詳細資訊,請參閱 伺服器端 ASP.NET Core Blazor的其他安全性案例。
請勿在伺服器端 Blazor 應用程式的 Razor 元件中直接或間接使用 IHttpContextAccessor/HttpContext。 Blazor 應用程式會在 ASP.NET Core 管線內容之外執行。 既不保證 HttpContext 在 IHttpContextAccessor 中可用,也不保證 HttpContext 會保留啟動了 Blazor 應用程式的內容。
建議在 Blazor 應用程式的初始轉譯期間,透過根元件參數將要求狀態傳遞給此應用程式。 或者,應用程式可以將資料複製到根元件初始化生命週期事件中的範圍服務,以便在整個應用程式中使用。 如需詳細資訊,請參閱伺服器端 ASP.NET Core Blazor 其他安全性案例。
伺服器端 Blazor 安全性的一個重要層面是,附加至指定線路的使用者可能會在建立 Blazor 線路後的某個時間點進行更新,但 IHttpContextAccessor不會更新。 如需使用自訂服務解決這種情況的詳細資訊,請參閱 伺服器端 ASP.NET CoreBlazor 其他安全性案例。
資源耗盡
當用戶端與伺服器互動並導致伺服器耗用過多資源時,可能會發生資源耗盡。 過度的資源耗用量主要會影響:
拒絕服務 (DoS) 的攻擊通常會試圖耗盡應用程式或伺服器的資源。 不過,資源耗盡不一定是系統攻擊的結果。 例如,有限資源可能會因為使用者需求過高而耗盡。 DoS 會在 DoS 一節中進一步說明。
Blazor 架構外部的資源,例如資料庫和檔案控制代碼 (用來讀取和寫入檔案),也可能會遇到資源耗盡。 如需詳細資訊,請參閱 ASP.NET Core 最佳做法。
CPU
當一或多個用戶端強制服務器執行密集 CPU 工作時,可能會發生 CPU 耗盡。
例如,請試想計算費波那契數的應用程式。 費波那契數是從費波那契序列產生,其中序列中的每個數字都是前兩個數字的總和。 到達答案所需的工作量取決於序列的長度和初始值的大小。 如果應用程式並未限制用戶端的要求,CPU 密集計算可能會佔用 CPU 的時間,並降低其他工作的效能。 過度的資源耗用量是會影響可用性的安全性考量。
CPU 耗盡是所有面向公用應用程式的問題。 在一般 Web 應用程式中,要求和連線逾時可作為保護措施,但 Blazor 應用程式不會提供相同的保護措施。 Blazor 應用程式必須包含適當的檢查和限制,才能執行潛在的 CPU 密集型工作。
記憶體
當一或多個用戶端強制服務器耗用大量的記憶體時,可能會發生記憶體耗盡。
例如,請試想應用程式具有可接受和顯示項目清單的元件。 如果 Blazor 應用程式並未限制允許的項目數目或轉譯回用戶端的項目數目,則記憶體密集的處理和轉譯可能會佔用伺服器的記憶體,進而達到伺服器效能受到影響的程度。 伺服器可能會當機或速度變慢到似乎已當機的程度。
請考慮下列案例,以維護和顯示與伺服器上潛在記憶體耗盡案例相關的項目清單:
List<T>
屬性或欄位中的項目會使用伺服器的記憶體。 如果應用程式允許項目清單未繫結,伺服器就會有記憶體不足的風險。 記憶體不足會導致目前的工作階段結束 (當機),而該伺服器執行個體中的所有並行工作階段都會收到記憶體不足的例外狀況。 若要避免發生此案例,應用程式必須使用資料結構來對並行使用者施加項目限制。- 如果未使用分頁配置進行轉譯,伺服器會針對 UI 中看不到的物件使用額外的記憶體。 若項目數目沒有限制,記憶體需求可能會耗盡可用的伺服器記憶體。 若要避免此案例,請使用下列其中一種方法:
- 在轉譯時使用編頁清單。
- 只顯示前 100 到 1,000 個項目,並要求使用者輸入搜尋準則,以尋找超出所顯示項目的項目。
- 如需更進階的轉譯案例,請實作支援虛擬化的清單或方格。 使用虛擬化時,清單只會轉譯使用者目前可見的項目子集。 當使用者與 UI 中的捲軸互動時,元件只會轉譯顯示所需的項目。 目前不需要顯示的項目可以保留在次要儲存體中,這是理想的方法。 未顯示的項目也可以保留在記憶體中,如此較不理想。
注意
Blazor 具有虛擬化的內建支援。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件虛擬化。
Blazor 應用程式為 WPF、Windows Forms 或 Blazor WebAssembly 等具狀態應用程式的其他 UI 架構提供類似的程式設計模型。 主要差異在於,在數個 UI 架構中,應用程式所耗用的記憶體屬於用戶端,且只會影響該個別用戶端。 例如,Blazor WebAssembly 應用程式會完全在用戶端上執行,且只會使用用戶端的記憶體資源。 針對伺服器端 Blazor 應用程式,應用程式所耗用的記憶體屬於伺服器,且會在伺服器執行個體上的用戶端之間共用。
伺服器端記憶體需求是所有伺服器端 Blazor 應用程式的考量。 不過,大部分的 Web 應用程式都是無狀態的,而處理要求時所使用的記憶體會在傳回回應時釋放。 作為一般建議,不允許用戶端配置未繫結的記憶體數量,如同在保存用戶端連線的任何其他伺服器端應用程式中。 伺服器端 Blazor 應用程式所耗用的記憶體會比單一要求持續更長一段時間。
注意
在開發期間,您可以使用分析工具或擷取的追蹤來評估用戶端的記憶體需求。 分析工具或追蹤不會擷取配置給特定用戶端的記憶體。 若要在開發期間擷取特定用戶端的記憶體使用情況,請擷取傾印,並檢查使用者線路上所有根目錄物件的記憶體需求。
用戶端連接
當一或多個用戶端開啟太多對於伺服器的並行連線時,可能會發生連線耗盡,使其他用戶端無法建立新的連線。
只要瀏覽器視窗開啟,Blazor 用戶端就會為每個工作階段建立單一連線,並讓連線保持開啟狀態。 鑒於連線的持續性本質和伺服器端 Blazor 應用程式的具狀態本質,連線耗盡對應用程式的可用性風險更大。
應用程式的每個使用者連線數目沒有限制。 如果應用程式需要連線限制,請採取下列一或多個方法:
- 需要驗證,這自然會限制未經授權使用者連線至應用程式的能力。 若要讓此案例生效,必須防止使用者視需要佈建新的使用者。
- 限制每個使用者的連線數目。 限制連線可以透過下列方法來完成。 謹慎地允許合法的使用者存取應用程式 (例如,根據用戶端的 IP 位址建立連線限制時)。
- 應用程式層級
- 端點路由擴充性。
- 需要驗證才能連線至應用程式,並追蹤每個使用者的作用中工作階段。
- 達到限制時拒絕新的工作階段。
- Proxy WebSocket 會透過使用 Proxy 連線至應用程式,例如多工處理從用戶端到應用程式連線的 Azure SignalR Service。 這可讓應用程式建立的連線容量大於單一用戶端可建立的容量,以防止用戶端耗盡與伺服器的連線。
- 伺服器層級
- 在應用程式前面使用 Proxy/閘道。 例如,Azure 應用程式閘道是網路流量 (OSI 第 7 層) 負載平衡器,可讓您管理 Web 應用程式的流量。 如需詳細資訊,請參閱應用程式閘道中的 WebSocket 支援概觀。
- 雖然允許採用 Azure Front Door 的 Blazor應用程式支援長輪詢,但 WebSockets 是建議的傳輸通訊協定。 自 2024 年 9 月起,Azure Front Door 不支援 WebSockets,但對 WebSocket 的支援正在考慮中。 如需詳細資訊,請參閱在 Azure Front Door上支援 WebSocket 連線。
- 應用程式層級
- 需要驗證,這自然會限制未經授權使用者連線至應用程式的能力。 若要讓此案例生效,必須防止使用者視需要佈建新的使用者。
- 限制每個使用者的連線數目。 限制連線可以透過下列方法來完成。 謹慎地允許合法的使用者存取應用程式 (例如,根據用戶端的 IP 位址建立連線限制時)。
- 應用程式層級
- 端點路由擴充性。
- 需要驗證才能連線至應用程式,並追蹤每個使用者的作用中工作階段。
- 達到限制時拒絕新的工作階段。
- Proxy WebSocket 會透過使用 Proxy 連線至應用程式,例如多工處理從用戶端到應用程式連線的 Azure SignalR Service。 這可讓應用程式建立的連線容量大於單一用戶端可建立的容量,以防止用戶端耗盡與伺服器的連線。
- 伺服器層級
- 在應用程式前面使用 Proxy/閘道。
- 雖然 Blazor 應用程式支援長輪詢,但 WebSockets 是建議的傳輸通訊協定。 我們建議您選取支援 WebSocket 的 Proxy/閘道。
- 應用程式層級
拒絕服務 (DoS) 的攻擊
拒絕服務 (DoS) 的攻擊牽涉到用戶端導致伺服器耗盡其一或多個資源,而使應用程式無法使用。 Blazor 應用程式包含預設限制,且依賴於其他 ASP.NET Core,以及在 CircuitOptions 上設定以防範 DoS 攻擊的 SignalR 限制:
- CircuitOptions.DisconnectedCircuitMaxRetained
- CircuitOptions.DisconnectedCircuitRetentionPeriod
- CircuitOptions.JSInteropDefaultCallTimeout
- CircuitOptions.MaxBufferedUnacknowledgedRenderBatches
- HubConnectionContextOptions.MaximumReceiveMessageSize
如需詳細資訊和設定程式碼撰寫範例,請參閱下列文章:
與瀏覽器的互動 (用戶端)
用戶端會透過分派和轉譯完成的 JS Interop 事件與伺服器互動。 JS Interop 通訊會在 JavaScript 與 .NET 之間雙向往來:
- 瀏覽器事件會以非同步方式從用戶端分派到伺服器。
- 伺服器會視需要以非同步方式重新轉譯 UI。
從 .NET 叫用的 JavaScript 函式
針對從 .NET 方法呼叫 JavaScript:
- 所有叫用都有可設定的逾時,且在逾時之後就會失敗,並將 OperationCanceledException 傳回給呼叫端。
- 呼叫的預設 (CircuitOptions.JSInteropDefaultCallTimeout) 逾時為一分鐘。 若要設定此限制,請參閱從 ASP.NET Core Blazor 中的 .NET 方法呼叫 JavaScript 函式。
- 您可以提供取消權杖來控制每個呼叫的取消。 如果提供取消權杖,則會依賴於預設呼叫逾時,並盡可能將任何呼叫時間繫結至用戶端。
- 無法信任 JavaScript 呼叫的結果。 在瀏覽器中執行的 Blazor 應用程式用戶端會搜尋要叫用的 JavaScript 函式。 系統會叫用函式,並產生結果或錯誤。 惡意用戶端可能會嘗試:
- 從 JavaScript 函式傳回錯誤,以在應用程式中造成問題。
- 從 JavaScript 函式傳回非預期的結果,以引發伺服器上的非預期行為。
採取下列預防措施來防範上述案例:
- 將 JS Interop 呼叫包裝在
try-catch
陳述式內,以考慮叫用期間可能發生的錯誤。 如需詳細資訊,請參閱處理 ASP.NET Core Blazor 應用程式中的錯誤。 - 在採取任何動作之前,先驗證從 JS Interop 叫用傳回的資料,包括錯誤訊息。
從瀏覽器叫用的 .NET 方法
請勿信任從 JavaScript 到 .NET 方法的呼叫。 當 .NET 方法公開至 JavaScript 時,請考慮如何叫用 .NET 方法:
- 將公開至 JavaScript 的任何 .NET 方法視為應用程式的公用端點。
- 驗證輸入。
- 確定值在預期的範圍內。
- 確定使用者有權執行所要求的動作。
- 請勿在 .NET 方法叫用中配置過多的資源數量。 例如,執行檢查並限制 CPU 和記憶體使用量。
- 考慮到靜態和執行個體方法可以公開給 JavaScript 用戶端。 除非設計要求使用適當條件約束共用狀態,否則請避免跨工作階段共用狀態。
- 對於透過原本透過相依性插入 (DI) 所建立 DotNetObjectReference 物件公開的執行個體方法,物件應該註冊為範圍物件。 這適用於應用程式使用的任何 DI 服務。
- 針對靜態方法,請避免建立無法限定於用戶端的狀態,除非應用程式在伺服器執行個體上的所有使用者之間刻意明確共用狀態。
- 避免將參數中使用者提供的資料傳遞至 JavaScript 呼叫。 如果絕對需要傳遞參數中的資料,請確定 JavaScript 程式碼會處理傳遞資料,而不會引入跨網站指令碼 (XSS) 弱點。 例如,請勿藉由設定元素的
innerHTML
屬性,將使用者提供的資料寫入 DOM。 請考慮使用內容安全性原則 (CSP) 來停用eval
和其他不安全的 JavaScript 基本類型。 如需詳細資訊,請參閱針對 ASP.NET Core Blazor 強制執行內容安全性原則。
- 驗證輸入。
- 請避免在架構的分派實作上實作 .NET 叫用的自訂分派。 將 .NET 方法公開至瀏覽器是進階案例,不建議用於一般 Blazor 開發。
事件
事件會提供應用程式的進入點。 保護 Web 應用程式中端點的相同規則適用於 Blazor 應用程式中的事件處理。 惡意用戶端可以傳送任何其想要傳送為事件承載的資料。
例如:
<select>
的變更事件可能會傳送不在應用程式呈現給用戶端選項內的值。<input>
可能會將任何文字資料傳送至伺服器,以略過用戶端驗證。
應用程式必須驗證應用程式所處理任何事件的資料。 Blazor 架構表單元件會執行基本驗證。 如果應用程式使用自訂表單元件,則必須撰寫自訂程式碼,才能視需要驗證事件資料。
事件屬於非同步,因此在應用程式有時間產生新的轉譯來回應之前,可以將多個事件分派到伺服器。 這有一些需要考慮的安全性影響。 限制應用程式中的用戶端動作必須在事件處理常式內執行,而不是取決於目前的轉譯檢視狀態。
請考慮應該允許使用者增量計數器最多三次的計數器元件。 增量計數器的按鈕會根據 count
的值有條件地使用:
<p>Count: @count</p>
@if (count < 3)
{
<button @onclick="IncrementCount" value="Increment count" />
}
@code
{
private int count = 0;
private void IncrementCount()
{
count++;
}
}
用戶端可以在架構產生此元件的新轉譯之前分派一或多個增量事件。 結果是 count
可由使用者增量三倍以上,因為 UI 移除按鈕的速度不夠快。 下列範例顯示達到三個 count
增量限制的正確方式:
<p>Count: @count</p>
@if (count < 3)
{
<button @onclick="IncrementCount" value="Increment count" />
}
@code
{
private int count = 0;
private void IncrementCount()
{
if (count < 3)
{
count++;
}
}
}
藉由在處理常式內新增 if (count < 3) { ... }
檢查,增量 count
的決策會以目前的應用程式狀態為基礎。 決策並非以 UI 的狀態為基礎,因為其在先前的範例中可能暫時過時。
防範多個分派
如果事件回呼以非同步方式叫用長時間執行的作業,例如從外部服務或資料庫擷取資料,請考慮使用防護。 當使用視覺效果回饋正在進行作業時,成立條件可防止使用者將多個作業加入佇列。 下列元件程式碼會在 DataService.GetDataAsync
從伺服器取得資料時,將 isLoading
設定為 true
。 當 isLoading
為 true
時,按鈕會在 UI 中停用:
<button disabled="@isLoading" @onclick="UpdateData">Update</button>
@code {
private bool isLoading;
private Data[] data = Array.Empty<Data>();
private async Task UpdateData()
{
if (!isLoading)
{
isLoading = true;
data = await DataService.GetDataAsync(DateTime.Now);
isLoading = false;
}
}
}
如果背景作業是使用 async
-await
模式以非同步方式執行,則上述範例中示範的防護模式可正常運作。
提前取消並避免處置後使用
除了使用 防範多個分派 一節中所述的防護,請考慮在處置元件時使用 CancellationToken 來取消長時間執行的作業。 此方法具有避免在元件中處置後使用的新增優點:
@implements IDisposable
...
@code {
private readonly CancellationTokenSource TokenSource =
new CancellationTokenSource();
private async Task UpdateData()
{
...
data = await DataService.GetDataAsync(DateTime.Now, TokenSource.Token);
if (TokenSource.Token.IsCancellationRequested)
{
return;
}
...
}
public void Dispose()
{
TokenSource.Cancel();
}
}
避免產生大量資料的事件
某些 DOM 事件,例如 oninput
或 onscroll
,可能會產生大量資料。 避免在伺服器端 Blazor 伺服器使用這些事件。
其他安全性指導
保護 ASP.NET Core 應用程式的指導適用於伺服器端 Blazor 應用程式,本文的下列各節涵蓋了:
記錄和敏感性資料
用戶端與伺服器之間的 JS Interop 互動會記錄在伺服器的記錄中,並包含 ILogger 執行個體。 Blazor 可避免記錄敏感性資訊,例如實際事件或 JS Interop 輸入和輸出。
當伺服器上發生錯誤時,架構會通知用戶端並卸載工作階段。 用戶端會收到可在瀏覽器開發人員工具中看到的一般錯誤訊息。
用戶端錯誤不包含呼叫堆疊,也不會提供錯誤原因的詳細資料,但伺服器記錄確實會包含此類資訊。 基於開發目的,您可以藉由啟用詳細的錯誤,將敏感性錯誤資訊提供給用戶端。
警告
將錯誤資訊公開給網際網路上的用戶端,是一律應避免的安全性風險。
使用 HTTPS 保護傳輸中的資訊
Blazor 會將 SignalR 用於用戶端與伺服器之間的通訊。 Blazor 通常會使用 SignalR 交涉的傳輸,通常是 WebSocket。
Blazor 不會確保伺服器與用戶端之間所傳送資料的完整性和機密性。 一律使用 HTTPS。
跨網站指令碼 (XSS)
跨網站指令碼 (XSS) 可讓未經授權的合作對象在瀏覽器的內容中執行任意邏輯。 遭入侵的應用程式可能會在用戶端上執行任意程式碼。 弱點可用來對伺服器執行一些惡意動作:
- 將假/無效事件分派至伺服器。
- 分派失敗/不正確轉譯完成。
- 避免分派轉譯完成。
- 將 Interop 呼叫從 JavaScript 分派至 .NET。
- 將 Interop 呼叫的回應從 .NET 修改為 JavaScript。
- 避免將 .NET 分派至 JS Interop 結果。
Blazor 架構會採取步驟來防範上述某些威脅:
- 如果用戶端不認可轉譯批次,則會停止產生新的 UI 更新。 使用 CircuitOptions.MaxBufferedUnacknowledgedRenderBatches 進行設定。
- 在一分鐘之後,將任何 .NET 逾時至 JavaScript 呼叫,而不會收到來自用戶端的回應。 使用 CircuitOptions.JSInteropDefaultCallTimeout 進行設定。
- 在 JS Interop 期間,對所有來自瀏覽器的輸入執行基本驗證:
- .NET 會參考有效且屬於 .NET 方法所預期的型別。
- 資料格式不正確。
- 方法的正確引數數目會出現在承載中。
- 在叫用方法之前,可以正確地還原序列化引數或結果。
- 在來自分派事件之瀏覽器的所有輸入中執行基本驗證:
- 事件具有有效的類型。
- 事件的資料可以還原序列化。
- 有與事件相關聯的事件處理常式。
除了架構所實作的保護措施之外,開發人員還必須撰寫應用程式的程式碼,才能防範威脅並採取適當的動作:
- 處理事件時一律驗證資料。
- 接收不正確資料時採取適當的動作:
- 忽略資料並傳回。 這可讓應用程式繼續處理要求。
- 如果應用程式判斷輸入是非法的,且無法由合法用戶端產生,則會擲回例外狀況。 擲回例外狀況會中斷線路並結束工作階段。
- 請勿信任記錄中所包含轉譯批次完成提供的錯誤訊息。 錯誤是由用戶端提供,且通常無法信任,因為用戶端可能會遭到入侵。
- 請勿信任 JavaScript 與 .NET 方法之間任一方向 JS Interop 呼叫上的輸入。
- 應用程式負責驗證引數的內容和結果是否有效,即使引數或結果已正確還原序列化也一樣。
若要讓 XSS 弱點存在,應用程式必須在轉譯的頁面中納入使用者輸入。 Blazor 會執行編譯時期步驟,其中 .razor
檔案中的標記會轉換成程式 C# 邏輯。 在執行階段,C# 邏輯會建置轉譯樹狀結構,以描述元素、文字和子元件。 這會透過 JavaScript 指令序列套用至瀏覽器的 DOM (或在預先轉譯的情況下序列化為 HTML):
- 透過一般 Razor 語法 (例如
@someStringValue
) 轉譯的使用者輸入不會公開 XSS 弱點,因為 Razor 語法是透過只能寫入文字的命令新增至 DOM。 即使值包含 HTML 標記,值也會顯示為靜態文字。 預先轉譯時,輸出會以 HTML 編碼,也會將內容顯示為靜態文字。 - 不允許指令碼標籤,且不應包含在應用程式的元件轉譯樹狀結構中。 如果元件標記中包含指令碼標籤,就會產生編譯時期錯誤。
- 元件作者可以在 C# 中撰寫元件,而不使用 Razor。 元件作者負責在發出輸出時使用正確的 API。 例如,使用
builder.AddContent(0, someUserSuppliedString)
而非builder.AddMarkupContent(0, someUserSuppliedString)
,因為後者可能會建立 XSS 弱點。
請考慮進一步降低 XSS 弱點。 例如,實作限制性的內容安全性原則 (CSP)。 如需詳細資訊,請參閱針對 ASP.NET Core Blazor 強制執行內容安全性原則。
如需詳細資訊,請參閱 ASP.NET Core 中的防止跨網站指令碼 (XSS)。
跨原始來源保護
跨原始來源攻擊涉及來自不同對伺服器執行動作之來源的用戶端。 惡意動作通常是 GET 要求或表單 POST (跨網站偽造要求、CSRF),但也可以開啟惡意的 WebSocket。 Blazor 應用程式會提供與使用中樞通訊協定供應項目之任何其他 SignalR 應用程式相同的保證:
- 除非採取其他措施來防止這麼做,否則可以跨原始來源存取應用程式。 若要停用跨原始來源存取,請將 CORS 中介軟體新增至管線,並將 DisableCorsAttribute 新增至 Blazor 端點中繼資料,或藉由為跨原始來源資源共用設定 SignalR 來限制允許的來源集合,以停用端點中的 CORS。 如需 WebSocket 來源限制的指導,請參閱 ASP.NET Core 中的 WebSocket 支援。
- 如果啟用 CORS,視 CORS 設定而定,可能需要額外的步驟來保護應用程式。 如果已全域啟用 CORS,則可以在端點路由產生器上呼叫 MapBlazorHub 之後,將 DisableCorsAttribute 中繼資料新增至端點中繼資料,以停用 BlazorSignalR 中樞的 CORS。
如需詳細資訊,請參閱防止 ASP.NET Core 中的跨網站要求偽造 (XSRF/CSRF) 攻擊。
點擊劫持
點擊劫持牽涉到將網站轉譯為來自不同來源網站內部的 <iframe>
,以便誘使使用者在遭受攻擊的網站上執行動作。
若要保護應用程式免於在 <iframe>
的內部進行轉譯,請使用內容安全性原則 (CSP) 和 X-Frame-Options
標頭。
如需詳細資訊,請參閱以下資源:
開放式重新導向
當應用程式工作階段啟動時,伺服器會執行在啟動工作階段期間傳送的 URL 基本驗證。 架構會在建立線路之前,先檢查基底 URL 是否為目前 URL 的父系。 架構不會執行任何其他檢查。
當使用者在用戶端上選取連結時,連結的 URL 會傳送至伺服器,以決定要採取的動作。 例如,應用程式可能會執行用戶端瀏覽,或指示瀏覽器移至新位置。
元件也可以透過使用 NavigationManager,以程式設計方式觸發瀏覽要求。 在這種情況下,應用程式可能會執行用戶端瀏覽,或指示瀏覽器移至新位置。
元件必須:
- 避免使用使用者輸入作為瀏覽呼叫引數的一部分。
- 驗證引數,以確保應用程式允許目標。
否則,惡意使用者可以強制瀏覽器移至網路攻擊者控制的網站。 在此案例中,網路攻擊者會誘使應用程式使用某些使用者輸入作為 NavigationManager.NavigateTo 方法叫用的一部分。
此建議也適用於將連結轉譯為應用程式的一部分:
- 可能的話,請使用相對連結。
- 先驗證絕對連結目的地是否有效,再將其包含在頁面中。
如需詳細資訊,請參閱防止 ASP.NET Core 中的開放式重新導向攻擊。
安全性檢查清單
下列安全性考量清單並不全面:
- 驗證來自事件的引數。
- 驗證 JS Interop 呼叫的輸入和結果。
- 避免使用 (或事先驗證) 使用者輸入,讓 .NET 進行 JS Interop 呼叫。
- 防止用戶端配置未繫結的記憶體數量。
- 元件內的資料。
- 傳回給用戶端的 DotNetObjectReference 物件。
- 防範多個分派。
- 處置元件時取消長時間執行的作業。
- 避免產生大量資料的事件。
- 避免在呼叫 NavigationManager.NavigateTo 期間使用使用者輸入,並在無法避免的情況下,先針對一組允許的來源驗證 URL 的使用者輸入。
- 請勿僅根據元件狀態中的 UI 狀態進行授權決策。
- 考慮使用內容安全性原則 (CSP) 來防範 XSS 攻擊。 如需詳細資訊,請參閱針對 ASP.NET Core Blazor 強制執行內容安全性原則。
- 請考慮使用 CSP 和 X-Frame-Options 來防範點擊劫持。
- 確定啟用 CORS 或明確停用 Blazor 應用程式的 CORS 時,CORS 設定是適當的。
- 測試以確保 Blazor 應用程式的伺服器端限制可提供可接受的使用者體驗,而沒有不可接受的風險層級。