首页 文章

AngularJS Web Api AntiForgeryToken CSRF

提问于
浏览
34

我有一个由 ASP.NET MVC 应用程序托管的 AngularJS 单页面应用程序(SPA) .
后端是 ASP.NET Web Api .

我想通过在 ASP.NET MVC 部分生成 AntiForgeryToken ,将其传递给 AngularJS ,然后让 Web Api 验证从后续 AngularJS 调用中收到的 AntiForgeryToken 来保护它免受 CSRF 攻击 .

“跨站点请求伪造(CSRF)是一种攻击,迫使最终用户在其当前已通过身份验证的Web应用程序上执行不需要的操作 . CSRF攻击专门针对状态更改请求,而不是数据被盗,因为攻击者无法查看对伪造请求的响应 . 通过社交工程的一些帮助(例如通过电子邮件或聊天发送链接),攻击者可以欺骗Web应用程序的用户执行攻击者选择的操作 . 如果受害者是普通用户,则成功的CSRF攻击可以强制用户执行状态更改请求,例如转移资金,更改其电子邮件地址等 . 如果受害者是管理帐户,CSRF可能会损害整个Web应用程序 . “ - 打开Web应用程序安全项目(OWASP)

3 回答

  • 0

    将__RequestVerificationToken添加到FormData

    var formData = new FormData();
        formData.append("__RequestVerificationToken", token);
        formData.append("UserName", $scope.kullaniciAdi);
        formData.append("Password", $scope.sifre);
    
        $http({
            method: 'POST',
            url: '/Login/Login',
            data: formData,
            transformRequest: angular.identity, 
            headers: { 'Content-Type': undefined }
    
        }).then(function successCallback(response) {
    
    
    
        }, function errorCallback(response) {
    
        });
    
  • 53

    添加到为AngularJS SPA提供服务的ASP.NET MVC视图中,假设是Views \ Home \ Index.cshtml,它是生成AntiForgeryToken的HTML帮助程序 .

    @Html.AntiForgeryToken();
    

    配置AngularJS将上面生成的AntiForgeryToken作为请求标头传递 .

    angular.module('app')
    .run(function ($http) {
        $http.defaults.headers.common['X-XSRF-Token'] =
            angular.element('input[name="__RequestVerificationToken"]').attr('value');
    });
    

    创建自定义Web API过滤器以验证所有非GET请求(PUT,PATCH,POST,DELETE) . 这假设您的所有GET请求都是安全的,不需要保护 . 如果不是这种情况,请删除if(actionContext.Request.Method.Method!=“GET”)排除项 .

    using System;
    using System.Linq;
    using System.Net.Http;
    using System.Web.Helpers;
    using System.Web.Http.Filters;
    
    namespace Care.Web.Filters
    {
        public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(
                System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                if (actionContext == null)
                {
                    throw new ArgumentNullException("actionContext");
                }
    
                if (actionContext.Request.Method.Method != "GET")
                {
                    var headers = actionContext.Request.Headers;
                    var tokenCookie = headers
                        .GetCookies()
                        .Select(c => c[AntiForgeryConfig.CookieName])
                        .FirstOrDefault();
    
                    var tokenHeader = string.Empty;
                    if (headers.Contains("X-XSRF-Token"))
                    {
                        tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
                    }
    
                    AntiForgery.Validate(
                        tokenCookie != null ? tokenCookie.Value : null, tokenHeader);
                }
    
                base.OnActionExecuting(actionContext);
            }
        }
    }
    

    在Global.asax.cs中将新创建的过滤器注册为全局过滤器 .

    private static void RegisterWebApiFilters(HttpFilterCollection filters)
        {
            filters.Add(new WebApiValidateAntiForgeryTokenAttribute());
        }
    

    或者,如果您不希望全局添加此过滤器,则只能将其放在某些Web API操作上,如下所示

    [WebApiValidateAntiForgeryToken]
    

    当然,这在定义上不太安全,因为总是有可能忘记将属性应用于需要它的动作 .

    另请注意,您必须拥有 Microsoft.AspNet.WebApi.Core 包才能访问 System.Web.Http 名称空间 . 您可以通过NuGet与 Install-Package Microsoft.AspNet.WebApi.Core 安装它 .

    这篇文章受到this blog post的启发 .

  • -1

    添加到ASP.NET MVC视图

    <Form ng-submit="SubmitForm(FormDataObject)">
            @Html.AntiForgeryToken()
            .....
            ...
            .
    </Form>
    

    然后在AngularJs控制器

    angular.module('myApp', []).controller('myController', function ($scope, $http, $httpParamSerializerJQLike) {
    
            $scope.antiForgeryToken = angular.element('input[name="__RequestVerificationToken"]').attr('value');
    
            $scope.SubmitForm = function (formData) {
                var dataRequest = {
                    __RequestVerificationToken: $scope.antiForgeryToken,
                    formData: angular.toJson(formData)
                };
    
                $http.post("/url/...", $httpParamSerializerJQLike(dataRequest), { headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }).then(function (response) {
                    $scope.result = JSON.parse(response.data);
                });
            }
        });
    

    为什么$ httpParamSerializerJQLike(dataRequest)?因为没有AngularJs将数据序列化为:

    {__RequestVerificationToken: blablabla, formData: blablabla}
    

    和Asp.NET MVC控制器抛出 The required anti-forgery form field “__RequestVerificationToken” is not present 错误 .

    但是如果使用$ httpParamSerializerJQLike(dataRequest)序列化请求数据,AngularJs将序列化为:

    __RequestVerificationToken: blablabla
    formData: blablabla
    

    和Asp.NET MVC控制器可以识别令牌而不会出现任何错误 .

相关问题