ASP.NET Core Blazor 靜態伺服器端轉譯的威脅風險降低指引
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明開發人員在使用靜態伺服器端轉譯開發 Blazor Web App時應考慮的安全性考量。
Blazor 會將三個不同的模型合而為一,以撰寫互動式 Web 應用程式。 傳統的伺服器端轉譯,這是以 HTTP 為基礎的要求/回應模型。 互動式伺服器端轉譯,這是以 SignalR 為基礎的轉譯模型。 最後,用戶端轉譯,這是以 WebAssembly 為基礎的轉譯模型。
當互動式元件以其中一個受支援的轉譯模式轉譯時,為互動式轉譯模式定義的所有一般安全性考量都套用至 Blazor Web App。 下列各節說明 Blazor Web App中非互動式伺服器端轉譯的特定安全性考量,以及轉譯模式彼此互動時所套用的特定層面。
伺服器端轉譯的一般考量
伺服器端轉譯 (SSR) 模型是以 HTTP 的傳統要求/回應模型為基礎。 因此,SSR 與要求/回應 HTTP 之間存在共同考慮的方面。 一般的安全性考量和特定的威脅風險必須成功降低。 架構提供內建的機制來管理這些其中的一些威脅,但其他的威脅是應用程式的程式碼特有的,必須由應用程式處理。 這些威脅可分類如下:
驗證和授權:應用程式必須確定使用者經過驗證並獲得授權,才能存取應用程式及其公開的資源。 架構提供用於驗證和授權的內建機制,但應用程式必須確保正確設定和使用這些機制。 Blazor 文件的伺服器 安全節點和 ASP.NET Core 文件的安全性和Identity 節點中介紹了用於驗證和授權的內建機制,因此這裡不再介紹。
輸入驗證和清理:來自用戶端的所有輸入在使用前必須經過驗證和清理。 否則,應用程式可能會暴露在攻擊 (例如 SQL 插入、跨網站指令碼、跨網站偽造要求、開放重新導向,以及其他形式的攻擊) 中。 輸入可能來自要求中的任何位置。
工作階段管理:正確管理使用者工作階段對於確保應用程式不會暴露在攻擊 (例如工作階段固定、工作階段劫持和其他攻擊) 中至關重要。 儲存在工作階段中的資訊必須受到適當的保護和加密,而且應用程式的程式碼必須防止惡意使用者猜測或操作工作階段。
錯誤處理和記錄:應用程式必須確保正確處理和記錄錯誤。 否則,應用程式可能會暴露在攻擊 (例如資訊洩漏) 中。 當應用程式在回應中傳回敏感性資訊,或當應用程式傳回包含可用於攻擊應用程式的資料的詳細錯誤訊息時,可能會發生這種情況。
資料保護:敏感性資料必須受到適當的保護 (其中包含在 WebAssembly 上執行時的應用程式邏輯),因為它可以輕易地進行反向工程。
阻斷服務:應用程式必須確保它不會暴露在攻擊 (例如阻斷服務) 中。 例如,當應用程式沒有適當的保護以防止暴力攻擊,或當某個動作可能導致應用程式消耗過多資源時,就會發生這種情況。
輸入驗證和清理
來自用戶端的所有輸入都必須被視為不受信任,除非其資訊是在伺服器上產生並受到保護,例如 CSRF 權杖、驗證 cookie、工作階段標識碼,或任何其他受已驗證加密保護的承載。
應用程式通常可以透過繫結程序來取得輸入,例如透過 [SupplyParameterFromQuery]
屬性 或 [SupplyParameterFromForm]
屬性。 在處理此輸入之前,應用程式必須確定資料有效。 例如,應用程式必須確認將表單資料對應到元件屬性時沒有任何繫結錯誤。 否則,應用程式可能會處理無效的資料。
如果輸入用來執行重新導向,則應用程式必須確保輸入有效,而且沒有指向被視為無效的網域或應用程式基本路徑內的無效子路徑。 否則,應用程式可能會暴露在開放的重新導向攻擊中,網路攻擊者可以在其中製作將使用者重新導向至惡意網站的連結。
如果輸入用來執行資料庫查詢,則應用程式必須確認輸入有效,而且不會讓應用程式遭受 SQL 插入式攻擊。 否則,網路攻擊者可能能夠製作可用於從資料庫中擷取資訊或修改資料庫的惡意查詢。
可能來自使用者輸入的資料也必須在包含在回應中之前進行清理。 例如,輸入可能包含可用於執行跨網站指令碼攻擊的 HTML 或 JavaScript,這可用來從使用者擷取資訊或代表使用者執行動作。
架構提供下列機制來協助進行輸入驗證和清理:
- 所有繫結的表單資料都會經過基本正確性的驗證。 如果輸入無法剖析,繫結程序會報告錯誤,應用程式可以在對資料採取任何動作之前發現該錯誤。 內建的 EditForm 元件在叫用 OnValidSubmit 表單回呼之前會考慮這一點。 如果存在一個或多個繫結錯誤,Blazor 會避免執行回呼。
- 架構會使用防偽權杖來防範跨網站要求偽造攻擊。 如需詳細資訊,請參閱 ASP.NET Core Blazor 驗證和授權和 ASP.NET Core Blazor 表單概觀。
在執行指定的動作時,必須在伺服器上驗證所有輸入與權限,以確保資料在該時間有效且準確並確保允許使用者執行該動作。 此方法與針對互動式伺服器端轉譯所提供的安全性指引一致。
工作階段管理
工作階段管理由架構處理。 架構會使用工作階段 cookie 來識別使用者工作階段。 工作階段 cookie 會使用 ASP.NET Core 資料保護 API 來進行保護。 在瀏覽器上執行的 JavaScript 程式碼無法存取工作階段 cookie,而且使用者無法輕易猜測或操作它。
關於其他工作階段資料 (例如儲存在服務內的資料),工作階段資料應該儲存在限定範圍的服務內,因為限定範圍的服務對於每個指定的使用者工作階段都是唯一的,這與在指定處理序執行個體中的所有使用者工作階段之間共用的單一服務相反。
在 SSR 方面,在大部分情況下,限定範圍的服務和暫時性的服務之間沒有太大差別,因為服務的存留期僅限於單一要求。 以下兩種情況有差別:
- 如果在要求期間該服務在多個位置或在不同時間被注入時。
- 如果該服務可能在互動式伺服器環境 (它會在多個轉譯中倖存下來,且其基本是該服務的範圍僅限於使用者工作階段) 中使用時。
錯誤處理和記錄
架構會在架構層級為應用程式提供內建的記錄。 架構會記錄重要的事件 (例如當表單的防偽權杖無法驗證時、當根元件開始轉譯時,以及當分派動作時)。 應用程式會負責記錄可能重要且要記錄的任何其他事件。
架構會在架構層級為應用程式提供內建的錯誤處理。 架構會處理元件轉譯期間所發生的錯誤,並使用錯誤界限機制來顯示易記的錯誤訊息,或允許錯誤向上升至例外狀況處理中介軟體 (其已設為呈現錯誤頁面)。
在回應開始被傳送至用戶端之後,串流轉譯期間所發生的錯誤會顯示在最終的回應中,做為一般的錯誤訊息。 錯誤原因的相關詳細資料只會在開發期間包含。
ASP.NET Core 資料保護
架構會提供機制來保護指定使用者工作階段的敏感性資訊,並確保內建元件會使用這些機制來保護敏感性資訊,例如在使用 cookie 驗證時保護使用者 identity。 在架構所處理的場景之外,開發人員的程式碼會負責保護其他應用程式特定的資訊。 執行此動作的最常見方式是透過 ASP.NET Core 資料保護() API 或任何其他形式的加密。 一般規則是應用程式負責:
- 確定使用者無法檢查或修改其他使用者的私人資訊。
- 確定使用者無法修改其他使用者的使用者資料,例如內部識別碼。
關於資料保護,您必須清楚了解程式碼在哪裡執行。 對於靜態伺服器端轉譯 (靜態 SSR) 和互動式伺服器端轉譯 (互動式 SSR),程式碼會儲存在伺服器上,且永遠不會到達用戶端。 對於互動式 WebAssembly 轉譯模式,應用程式的程式碼一律會到達用戶端,這表示任何儲存在應用程式的程式碼中的敏感性資訊都可供有權存取該應用程式的任何人使用。 混淆和其他類似的技術來「保護」程式碼都是無效的。 一旦程式碼到達用戶端,就可以進行反向工程來擷取敏感性資訊。
拒絕服務
在伺服器層級,架構會提供要求/回應參數的限制,例如要求的大小上限和標頭大小。 關於應用程式的程式碼,Blazor 的表單對應系統會定義類似於 MVC 模型繫結系統所定義的限制:
- 最大錯誤數的限制。
- 繫結器最大遞迴深度的限制。
- 集合中繫結的最大元素數的限制。
此外,也為表單定義了一些限制,例如最大表單索引鍵大小和值大小以及最大項目數。
一般而言,應用程式必須評估要求何時有可能會觸發伺服器的不對稱工作量。 這樣的範例包括當使用者傳送由 N 參數化的要求且伺服器執行回應作業的成本是 N 倍時 (其中 N 是使用者控制且可無限增長的參數)。 通常,應用程式必須對其願意處理的最大 N 施加限制,或確保任何作業的成本比要求少、等於或高一個常數因子。
這個層面與用戶端執行的工作和伺服器執行的工作之間的成長差異有關,而不是與特定的 1→N 比較有關。 例如,用戶端可能會提交工作專案(將元素插入清單),需要 N 個時間單位才能執行,但伺服器需要 N2 來處理(因為它可能會執行非常天真的事)。 N 和 N2 之間的差異很重要。
因此,伺服器必須願意執行的工作量是有限制的,這是應用程式特有的限制。 此層面適用於伺服器端的工作負載,因為資源位於伺服器上,但在大多數情況下不一定適用於用戶端上的 WebAssembly 工作負載。
另一個重要的層面是,這不僅僅是保留給 CPU 時間。 它也適用於任何資源,例如記憶體、網路和磁碟空間。
對於 WebAssembly 工作負載,通常很少顧慮到用戶端執行的工作量,因為用戶端通常受到用戶端上可用資源的限制。 不過,在某些情況下,用戶端可能會受到影響,例如,如果某個應用程式顯示來自其他使用者的資料,而且有一位使用者能夠將資料新增至系統,來迫使顯示資料的用戶端執行與該使用者所新增的資料量不成比例的工作量。
建議 (非詳盡) 的檢查清單
- 確保使用者經過驗證並授權存取應用程式及其公開的資源。
- 先驗證並清理來自用戶端的所有輸入,再使用它。
- 適當管理使用者工作階段,以確保狀態不會在使用者之間錯誤地共用。
- 適當處理和記錄錯誤,以避免公開敏感性資訊。
- 記錄應用程式中的重要事件,以識別潛在的問題並稽核使用者所執行的動作。
- 使用 ASP.NET Core 資料保護 API 或其中一個可用元件 (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage、PersistentComponentState) 來保護敏感性資訊。
- 確保應用程式了解可由指定要求取用的資源,並設定限制以避免阻斷服務攻擊。