jQuery Ajax 调用和 Html.AntiForgeryToken()
我已经按照我阅读的信息在我的应用程序中实施了对 CSRF 攻击 的缓解措施在互联网上的一些博客文章上。特别是这些帖子是我实施的驱动力
- ASP.NET MVC 最佳实践,来自 ASP.NET 和 Web 工具开发人员内容团队
- 跨站请求伪造攻击剖析 来自 Phil Haack 博客
- ASP.NET MVC 框架中的 AntiForgeryToken - Html.AntiForgeryToken 和 ValidateAntiForgeryToken 属性 来自 David Hayden 博客
基本上,这些文章和建议表明,为了防止 CSRF 攻击,任何人都应该实现以下代码:
在接受 POST Http 动词的每个操作上添加
[ValidateAntiForgeryToken]
[HttpPost] [验证防伪令牌] 公共 ActionResult SomeAction( SomeModel 模型 ) { }
在向服务器提交数据的表单中添加
<%= Html.AntiForgeryToken() %>
帮助程序
无论如何,在我的应用程序的某些部分,我正在使用 jQuery 向服务器执行 Ajax POST,而无需任何操作形式根本。例如,当我让用户单击图像来执行特定操作时,就会发生这种情况。
假设我有一个包含活动列表的表。我在表格的一列上有一个图像,上面写着“将活动标记为已完成”,当用户单击该活动时,我正在执行 Ajax POST,如以下示例所示:
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {},
success: function (response) {
// ....
}
});
});
如何使用 <%= Html.AntiForgeryToken() %>
在这些情况下?我应该在 Ajax 调用的数据参数中包含帮助程序调用吗?
抱歉发了这么长的帖子,非常感谢您帮助
编辑:
根据jayrdub 答案我已按以下方式使用
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {
AddAntiForgeryToken({}),
id: parseInt($(this).attr("title"))
},
success: function (response) {
// ....
}
});
});
I have implemented in my app the mitigation to CSRF attacks following the informations that I have read on some blog post around the internet. In particular these post have been the driver of my implementation
- Best Practices for ASP.NET MVC from the ASP.NET and Web Tools Developer Content Team
- Anatomy of a Cross-site Request Forgery Attack from Phil Haack blog
- AntiForgeryToken in the ASP.NET MVC Framework - Html.AntiForgeryToken and ValidateAntiForgeryToken Attribute from David Hayden blog
Basically those articles and recommendations says that to prevent the CSRF attack anybody should implement the following code:
Add the
[ValidateAntiForgeryToken]
on every action that accept the POST Http verb[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}Add the
<%= Html.AntiForgeryToken() %>
helper inside forms that submits data to the server
Anyway in some parts of my app I am doing Ajax POSTs with jQuery to the server without having any form at all. This happens for example where I am letting the user to click on an image to do a specific action.
Suppose I have a table with a list of activities. I have an image on a column of the table that says "Mark activity as completed" and when the user click on that activity I am doing the Ajax POST as in the following sample:
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {},
success: function (response) {
// ....
}
});
});
How can I use the <%= Html.AntiForgeryToken() %>
in these cases? Should I include the helper call inside the data parameter of the Ajax call?
Sorry for the long post and thanks very much for helping out
EDIT:
As per jayrdub answer I have used in the following way
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {
AddAntiForgeryToken({}),
id: parseInt($(this).attr("title"))
},
success: function (response) {
// ....
}
});
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(21)
我正在使用 ajax post 来运行删除方法(恰好来自 visjs 时间线,但这不相关)。这就是我的:
这是我的 Index.cshtml
我在此处添加的所有内容是
@Html.AntiForgeryToken()
以使令牌出现在页面中然后在我的 ajax 帖子中我使用了:
其中添加了令牌值,从页面上刮下来,到发布的字段
在此之前,我尝试将值放入标题中,但遇到了相同的错误,
请随意发布改进。这似乎是一个我可以理解的简单方法
I'm using a ajax post to run a delete method (happens to be from a visjs timeline but that's not relelvant). This is what I sis:
This is my Index.cshtml
All I added here was
@Html.AntiForgeryToken()
to make the token appear in the pageThen in my ajax post I used:
Which adds the token value, scraped off the page, to the fields posted
Before this I tried putting the value in the headers but I got the same error
Feel free to post improvements. This certainly seems to be a simple approach that I can understand
好吧,这里有很多帖子,但没有一个对我有帮助,谷歌日复一日,我仍然没有进一步,我从头开始编写整个应用程序,然后我注意到我的 Web.confg 中的这个小金块
现在我不知道为什么我添加了它,但我后来注意到,它在调试模式下被忽略,而不是在生产模式下(IE安装到IIS某处)
对我来说,解决方案是两个选项之一,因为我不记得为什么我添加了它,我不能确定其他事情不依赖于它,其次,域名必须全部小写,并且 TLD 不像我在 *.localLookup.net 中所做的那样,
也许它有帮助,也许没有。我希望它能帮助某人
Okay lots of posts here, none of them helped me, days and days of google, and still no further I got to the point the wr-writing the whole app from scratch, and then I noticed this little nugget in my Web.confg
Now I don't know why I added it however I have since noticed, its ignored in debug mode and not in a production mode (IE Installed to IIS Somewhere)
For me the solution was one of 2 options, since I don't remember why I added it I cant be sure other things don't depend on it, and second the domain name must be all lower case and a TLD not like ive done in *.localLookup.net
Maybe it helps maybe it don't. I hope it does help someone
我找到的解决方案不是针对 ASPX,而是针对 Razor,但是相当可比的问题。
我通过将 AntiForgery 添加到请求中解决了这个问题。 HTML Helper 不会通过调用创建 HTML id
为了将令牌添加到 postrequest,我刚刚使用 jquery 将 AntiForgery id 添加到隐藏字段:
这导致控制器接受带有 [ValidateAntiForgeryToken] 属性的请求
The Solution i found is not for ASPX but for Razor, but quite comperable issue.
I resolved it by adding the AntiForgery to the request. The HTML Helper does not create a HTML id with the call
In order to add the token to the postrequest i just added the AntiForgery id to the hidden field with jquery:
This caused the controller to accept the request with the [ValidateAntiForgeryToken] attribute
上面的大部分答案都是针对 MVC 应用程序的。是的,您需要添加
@Html.AntiForgeryToken() 在您的 cshtml 文件上,并获取 js 文件中的安全令牌并将其用于 ajax post 的数据对象。
然而,在 C# 方面,请注意,如果您使用 Razor 页面,请注意您不能在方法顶部使用 [ValidateAntiForgeryToken] 属性。它不会给你一个错误,但不会有任何影响,因为它只适用于 MVC 应用程序。对于 razor 页面,您需要使用“model”类之上的属性。
例如;
这会将属性应用于页面上的所有方法。
Most of the answers above are for MVC applications. Yes, you need to add
@Html.AntiForgeryToken() on your cshtml file and also get the security token in the js file and use it on you ajax post's data object.
However on the c# side, just a reminder, if you are using Razor pages, note that you cannot use [ValidateAntiForgeryToken] attribute on top of the methods. It will not give you an error but it will not have any effect since it only works on MVC apps. For razor pages, you need to use the attribute on top of the "model" class.
For example;
This will apply the attribute to all the methods on the page.
AntiforgeryToken 仍然是一个痛苦,上面的例子对我来说都没有一个字对我有效。那里太多了。所以我把它们全部结合起来。需要一个 @Html.AntiforgeryToken 以挂在 iirc 周围的形式
解决如下:
如有疑问,添加更多 $ 符号
AntiforgeryToken is still a pain, none of the examples above worked word for word for me. Too many for's there. So I combined them all. Need a @Html.AntiforgeryToken in a form hanging around iirc
Solved as so:
When in doubt, add more $ signs
我使用像这样的简单js函数
因为页面上的每个表单都具有相同的令牌值,所以只需将类似的内容放在最顶层的母版页中
然后在ajax调用中执行(编辑以匹配您的第二个示例)
I use a simple js function like this
Since every form on a page will have the same value for the token, just put something like this in your top-most master page
Then in your ajax call do (edited to match your second example)
我喜欢360Airwalk提供的解决方案,但可能还需要改进一些。
第一个问题是,如果您使用空数据创建
$.post()
,jQuery 不会添加Content-Type
标头,在本例中为 ASP.NET MVC无法接收和检查令牌。所以你必须确保标题始终存在。另一个改进是支持所有带有内容的 HTTP 动词:POST、PUT、DELETE 等。虽然您可能在应用程序中仅使用 POST,但最好有一个通用的解决方案并验证您收到的所有数据任何动词都有防伪标记。
I like the solution provided by 360Airwalk, but it may be improved a bit.
The first problem is that if you make
$.post()
with empty data, jQuery doesn't add aContent-Type
header, and in this case ASP.NET MVC fails to receive and check the token. So you have to ensure the header is always there.Another improvement is support of all HTTP verbs with content: POST, PUT, DELETE etc. Though you may use only POSTs in your application, it's better to have a generic solution and verify that all data you receive with any verb has an anti-forgery token.
我知道还有很多其他答案,但这篇文章很好而且简洁,迫使您检查所有 HttpPost,而不仅仅是其中的一些:
http://richiban.wordpress.com/2013/02/06/validating-net -mvc-4-anti-forgery-tokens-in-ajax-requests/
它使用 HTTP 标头而不是尝试修改表单集合。
服务器
客户端
I know there are a lot of other answers, but this article is nice and concise and forces you to check all of your HttpPosts, not just some of them:
http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/
It uses HTTP headers instead of trying to modify the form collection.
Server
Client
我在这里感觉自己像个高级死灵法师,但这在 4 年后的 MVC5 中仍然是一个问题。
为了正确处理 ajax 请求,需要在 ajax 调用时将防伪令牌传递到服务器。将其集成到您的发布数据和模型中是混乱且不必要的。将令牌添加为自定义标头是干净且可重用的 - 并且您可以对其进行配置,这样您就不必每次都记住执行此操作。
有一个例外 - Unobtrusive ajax 不需要对 ajax 调用进行特殊处理。令牌照常在常规隐藏输入字段中传递。与常规 POST 完全相同。
_Layout.cshtml
在 _layout.cshtml 中我有这个 JavaScript 块。它不会将标记写入 DOM,而是使用 jQuery 从 MVC Helper 生成的隐藏输入文字中提取它。作为标头名称的 Magic 字符串被定义为属性类中的常量。
请注意 beforeSend 函数中使用单引号 - 呈现的输入元素使用双引号,这会破坏 JavaScript 文字。
客户端 JavaScript
当执行上面的 beforeSend 函数时,会自动调用 AntiForgeryToken添加到请求标头中。
服务器库
需要自定义属性来处理非标准令牌。这建立在 @viggity 的解决方案之上,但可以正确处理不引人注目的 ajax。该代码可以隐藏在您的公共库
服务器/控制器
中现在您只需将该属性应用于您的操作即可。更好的是,您可以将该属性应用于控制器,并且所有请求都将得到验证。
I feel like an advanced necromancer here, but this is still an issue 4 years later in MVC5.
To handle ajax requests properly the anti-forgery token needs to be passed to the server on ajax calls. Integrating it into your post data and models is messy and unnecessary. Adding the token as a custom header is clean and reusable - and you can configure it so you don't have to remember to do it every time.
There is an exception - Unobtrusive ajax does not need special treatment for ajax calls. The token is passed as usual in the regular hidden input field. Exactly the same as a regular POST.
_Layout.cshtml
In _layout.cshtml I have this JavaScript block. It doesn't write the token into the DOM, rather it uses jQuery to extract it from the hidden input literal that the MVC Helper generates. The Magic string that is the header name is defined as a constant in the attribute class.
Note the use of single quotes in the beforeSend function - the input element that is rendered uses double quotes that would break the JavaScript literal.
Client JavaScript
When this executes the beforeSend function above is called and the AntiForgeryToken is automatically added to the request headers.
Server Library
A custom attribute is required to process the non standard token. This builds on @viggity's solution, but handles unobtrusive ajax correctly. This code can be tucked away in your common library
Server / Controller
Now you just apply the attribute to your Action. Even better you can apply the attribute to your controller and all requests will be validated.
不要使用Html.AntiForgeryToken。相反,请使用 Web API 中的 AntiForgery.GetTokens 和 AntiForgery.Validate,如 防止 ASP.NET MVC 应用程序中的跨站请求伪造 (CSRF) 攻击 。
Don't use Html.AntiForgeryToken. Instead, use AntiForgery.GetTokens and AntiForgery.Validate from Web API as described in Preventing Cross-Site Request Forgery (CSRF) Attacks in ASP.NET MVC Application.
我认为您所要做的就是确保“__RequestVerificationToken”输入包含在 POST 请求中。另一半信息(即用户 cookie 中的令牌)已通过 AJAX POST 请求自动发送。
例如,
I think all you have to do is ensure that the "__RequestVerificationToken" input is included in the POST request. The other half of the information (i.e. the token in the user's cookie) is already sent automatically with an AJAX POST request.
E.g.,
我刚刚在当前的项目中实现了这个实际问题。我为所有需要经过身份验证的用户的 ajax-POST 执行了此操作。
首先,我决定挂接我的 jquery ajax 调用,这样我就不会太频繁地重复自己。这个 javascript 片段确保所有 ajax (post) 调用都会将我的请求验证令牌添加到请求中。注意:名称 __RequestVerificationToken 由 .Net 框架使用,因此我可以利用标准的反 CSRF 功能,如下所示。
在您需要令牌可用于上述 JavaScript 的视图中,只需使用常见的 HTML 帮助程序即可。基本上你可以在任何你想要的地方添加这段代码。我将其放在 if(Request.IsAuthenticated) 语句中:
在您的控制器中,只需使用标准 ASP.Net MVC 反 CSRF 机制。我是这样做的(虽然我实际上使用了盐)。
使用 Firebug 或类似工具,您可以轻松查看 POST 请求现在如何附加 __RequestVerificationToken 参数。
I was just implementing this actual problem in my current project. i did it for all ajax-POSTs that needed an authenticated user.
First off i decided to hook my jquery ajax calls so i do not to repeat myself too often. this javascript snippet ensures all ajax (post) calls will add my request validation token to the request. Note: the name __RequestVerificationToken is used by the .Net framework so i can utilize the standard Anti-CSRF features as shown below.
In your Views where you need the token to be available to the above javascript just use the common HTML-Helper. You can basically add this code whereever you want. I placed it within a if(Request.IsAuthenticated) statement:
In your controller simply use the standard ASP.Net MVC Anti-CSRF mechanism. I did it like this (though i actually used Salt).
With Firebug or a similar tool you can easily see how your POST requests now have a __RequestVerificationToken parameter appended.
您也可以这样做:
这是使用
Razor
,但如果您使用WebForms
语法,您也可以使用<%= %>< /代码> 标签
You can do this also:
This is using
Razor
, but if you're usingWebForms
syntax you can just as well use<%= %>
tags除了我对 @JBall 的答案的评论之外,这对我一路以来都有帮助,这是对我有用的最终答案。我正在使用 MVC 和 Razor,并且正在使用 jQuery AJAX 提交表单,因此我可以使用一些新结果更新部分视图,并且我不想进行完整的回发(和页面闪烁)。
像平常一样在表单中添加
@Html.AntiForgeryToken()
。我的 AJAX 提交按钮代码(即 onclick 事件)是:
我保留了“成功”操作,因为它显示了如何更新包含 MvcJqGrid 的部分视图以及如何刷新它(非常强大的 jqGrid 网格,这是一个出色的 MVC 包装器)。
我的控制器方法如下所示:
我必须承认我不喜欢将整个表单的数据发布为模型,但如果您需要这样做,那么这是一种可行的方法。 MVC 只是让数据绑定变得太容易了,所以我想,这比提交 16 个单独的值(或弱类型的 FormCollection)还好。如果您更了解,请告诉我,因为我想生成健壮的 MVC C# 代码。
Further to my comment against @JBall's answer that helped me along the way, this is the final answer that works for me. I'm using MVC and Razor and I'm submitting a form using jQuery AJAX so I can update a partial view with some new results and I didn't want to do a complete postback (and page flicker).
Add the
@Html.AntiForgeryToken()
inside the form as usual.My AJAX submission button code (i.e. an onclick event) is:
I've left the "success" action in as it shows how the partial view is being updated that contains an MvcJqGrid and how it's being refreshed (very powerful jqGrid grid and this is a brilliant MVC wrapper for it).
My controller method looks like this:
I have to admit to not being a fan of POSTing an entire form's data as a Model but if you need to do it then this is one way that works. MVC just makes the data binding too easy so rather than subitting 16 individual values (or a weakly-typed FormCollection) this is OK, I guess. If you know better please let me know as I want to produce robust MVC C# code.
从 https://gist.github.com/scottrippey/3428114 中发现了这个非常聪明的想法$.ajax 调用它修改请求并添加令牌。
found this very clever idea from https://gist.github.com/scottrippey/3428114 for every $.ajax calls it modifies the request and add the token.
1.定义从服务器获取令牌的函数
2.在发送到服务器之前获取令牌并设置标头
3.在处理 Post/get 的方法上对 HttpRequestBase 进行 Onserver 验证
1.Define Function to get Token from server
2.Get token and set header before send to server
3. Onserver Validation on HttpRequestBase on method you handle Post/get
我知道这个问题发布已经有一段时间了,但我发现了非常有用的资源,其中讨论了 AntiForgeryToken 的用法并使其使用起来不那么麻烦。它还提供 jquery 插件,以便在 AJAX 调用中轻松包含防伪令牌:
ASP.NET MVC 和 AJAX 的防伪造请求配方
I我贡献不多,但也许有人会发现它很有用。
I aware it's been some time since this question was posted, but I found really useful resource, which discusses usage of AntiForgeryToken and makes it less troublesome to use. It also provides jquery plugin for easily including antiforgery token in AJAX calls:
Anti-Forgery Request Recipes For ASP.NET MVC And AJAX
I'm not contributing much, but maybe someone will find it useful.
这是我见过的最简单的方法。注意:确保您的视图中有“@Html.AntiForgeryToken()”
Here is the easiest way I've seen. Note: Make sure you have "@Html.AntiForgeryToken()" in your View
对 360Airwalk 解决方案略有改进。这会将防伪造令牌嵌入到 javascript 函数中,因此 @Html.AntiForgeryToken() 不再需要包含在每个视图中。
Slight improvement to 360Airwalk solution. This imbeds the Anti Forgery Token within the javascript function, so @Html.AntiForgeryToken() no longer needs to be included on every view.