AngularJS Web Api AntiForgeryToken CSRF
Posted
技术标签:
【中文标题】AngularJS Web Api AntiForgeryToken CSRF【英文标题】: 【发布时间】:2015-12-04 06:43:27 【问题描述】:我有一个由 ASP.NET MVC 应用程序托管的 AngularJS 单页应用程序 (SPA)。 后端是 ASP.NET Web Api。
我想通过在 ASP.NET MVC 部分生成AntiForgeryToken
来保护它免受 CSRF 攻击,并将其传递给 AngularJS,然后让 Web Api 验证从后续 AngularJS 调用收到的 AntiForgeryToken
。
“跨站请求伪造 (CSRF) 是一种强制结束的攻击 用户在他们所在的 Web 应用程序上执行不需要的操作 目前已通过身份验证。 CSRF 攻击专门针对 状态改变请求,而不是窃取数据,因为攻击者没有 查看对伪造请求的响应的方法。在一点帮助下 社会工程(例如通过电子邮件或聊天发送链接), 攻击者可能会诱骗 Web 应用程序的用户执行 攻击者选择的动作。如果受害者是普通用户,则 成功的 CSRF 攻击可以强制用户执行状态更改 诸如转移资金、更改电子邮件地址等请求 向前。如果受害者是管理帐户,CSRF 可能会妥协 整个 Web 应用程序。” - 开放网络应用程序安全项目 (OWASP)
【问题讨论】:
【参考方案1】:添加到服务于 AngularJS SPA 的 ASP.NET MVC 视图,比如说
Views\Home\Index.cshtml
, 生成AntiForgeryToken
.
@Html.AntiForgeryToken();
配置AngularJS 将上面生成的
AntiForgeryToken
作为Request Header 传递。
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
命名空间。您可以使用Install-Package Microsoft.AspNet.WebApi.Core
通过 NuGet 安装它。
这篇文章深受this blog post 的启发。
【讨论】:
很抱歉这个问题,但通常的做法是提出问题并立即给出准备好的答案吗? 是的。您可以在此处阅读更多信息:blog.stackexchange.com/2011/07/…。 @Mihai-AndreiDinculescu 如果页面上有超过 1 个令牌,这仍然有效吗?可能有超过 1 个表单,这意味着超过 1 个带有令牌的隐藏输入。 @onefootswill 是的,很明显。但是为什么你会在一页上有多个令牌?一个人应该满足所有的要求。您无需将其包含在您的表单中。将它放在 body 标签内容的开头或结尾。 @onefootswill 如果您有多个表单,您应该只生成一次令牌。它应该服务于那个request而不是一个单独的表单。【参考方案2】:将 __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)
);
【讨论】:
【参考方案3】:添加到 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 控制器抛出所需的防伪表单字段“__RequestVerificationToken”不存在错误。
但是如果你序列化请求数据 $httpParamSerializerJQLike(dataRequest),AngularJs 序列化为:
__RequestVerificationToken: blablabla
formData: blablabla
并且 Asp.NET MVC 控制器可以识别 Token 而不会出现任何错误。
【讨论】:
以上是关于AngularJS Web Api AntiForgeryToken CSRF的主要内容,如果未能解决你的问题,请参考以下文章
[angularjs] MVC + Web API + AngularJs 搭建简单的 CURD 框架
AngularJS Web Api AntiForgeryToken CSRF
使用 web api 和 angularjs 下载 excel 文件