使用 WebApi 時防偽 cookie 令牌和表單欄位令牌不匹配
我有一個單頁應用程序(使用者載入一堆 HTML/JS,然後發出 AJAX 請求而無需再次呼叫 MVC - 僅通過 WebAPI)。在 WebAPI 中,我有以下內容:
public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute { public override void OnActionExecuting( System.Web.Http.Controllers.HttpActionContext actionContext) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (actionContext.Request.Method.Method == "POST") { string requestUri = actionContext.Request.RequestUri.AbsoluteUri.ToLower(); if (uriExclusions.All(s => !requestUri.Contains(s, StringComparison.OrdinalIgnoreCase))) // place some exclusions here if needed { HttpRequestHeaders headers = actionContext.Request.Headers; CookieState tokenCookie = headers .GetCookies() .Select(c => c[AntiForgeryConfig.CookieName]) // __RequestVerificationToken .FirstOrDefault(); string tokenHeader = string.Empty; if (headers.Contains("X-XSRF-Token")) { tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault(); } AntiForgery.Validate(!string.IsNullOrEmpty(tokenCookie?.Value) ? tokenCookie.Value : null, tokenHeader); } } base.OnActionExecuting(actionContext); // this is where it throws } }在 Global.asax 註冊:
private static void RegisterWebApiFilters(HttpFilterCollection filters) { filters.Add(new WebApiValidateAntiForgeryTokenAttribute()); filters.Add(new AddCustomHeaderFilter()); }有時,我會
The anti-forgery cookie token and form field token do not match在日誌中看到錯誤。發生這種情況時,兩者tokenCookie.value和tokenHeader都不為空。客戶端,我所有的 AJAX 請求都使用以下內容:
beforeSend: function (request) { request.setRequestHeader("X-XSRF-Token", $('input[name="__RequestVerificationToken"]').attr("value");); },使用 Razor 在我的 SPA 頁面上生成一次令牌:
@Html.AntiForgeryToken()我在 Web.config 中設置了我的機器密鑰。
這可能是什麼原因造成的?
更新 我剛剛檢查了日誌,有時我也會看到:
提供的防偽令牌用於使用者“”,但目前使用者是“someuser@domain.com”。幾秒鐘前
當使用者在登錄時刷新他們的 SPA 實例時會發生這種情況。然後 SPA 出於某種原因將它們放入登錄頁面而不是內部頁面(
User.Identity.IsAuthenticated為真) - 然後由於此錯誤,他們無法登錄。清爽將它們拉回室內。不知道這意味著什麼,但我認為更多資訊不會受到傷害。
我的回答將建議不要嘗試在 AJAX 呼叫中使用基於令牌的 CSRF 保護,而是依賴 Web 瀏覽器的本機 CORS 功能。
基本上,從瀏覽器到後端伺服器的任何 AJAX 呼叫都將檢查域來源(也就是載入腳本的域)。如果域匹配(JS 託管域 == 目標 AJAX 伺服器域)AJAX 呼叫執行良好,否則返回
null.如果攻擊者試圖在他自己的伺服器上託管惡意 AJAX 查詢,如果您的後端伺服器沒有允許他這樣做的 CORS 策略(預設情況下就是這種情況),它將失敗。
因此,從本質上講,CSRF 保護在 AJAX 呼叫中毫無用處,您可以通過簡單地不嘗試處理來降低您的技術債務。
有關 CORS的更多資訊- Mozilla 基金會
程式碼範例 - 使用您的控制台檢查器!
<html> <script> function reqListener () { console.log(this.responseText); } var oReq = new XMLHttpRequest(); oReq.addEventListener("load", reqListener); oReq.open("GET", "http://www.reuters.com/"); oReq.send(); </script> </html>執行它並查看安全錯誤:
跨域請求被阻止:同源策略不允許讀取http://www.reuters.com/上的遠端資源。(原因:缺少 CORS 標頭“Access-Control-Allow-Origin”)。
Mozilla 對跨站點 XMLHttpRequest實現非常清楚:
現代瀏覽器通過實施 Web 應用程序 (WebApps) 工作組的跨站點請求訪問控制標準來支持跨站點請求。
只要將伺服器配置為允許來自您的 Web 應用程序的請求,XMLHttpRequest 就可以工作。否則,將引發 INVALID_ACCESS_ERR 異常。