Asp.net

使用 WebApi 時防偽 cookie 令牌和表單欄位令牌不匹配

  • August 8, 2017

我有一個單頁應用程序(使用者載入一堆 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.valuetokenHeader都不為空。

客戶端,我所有的 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為真) - 然後由於此錯誤,他們無法登錄。清爽將它們拉回室內。不知道這意味著什麼,但我認為更多資訊不會受到傷害。

附錄 https://security.stackexchange.com/questions/167064/is-csrf-protection-useless-with-ajax/167076#167076

我的回答將建議不要嘗試在 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 異常。

引用自:https://stackoverflow.com/questions/45389512