我已经在我的应用程序中实现了对CSRF攻击的缓解,这是我在互联网上的一些博客文章上读到的信息。特别是这些帖子一直是我实现的驱动力
ASP的最佳实践。NET MVC从ASP。NET和Web工具开发人员内容团队
跨站点请求伪造攻击的剖析,来自Phil Haack的博客
ASP中的AntiForgeryToken。NET MVC框架- Html。来自David Hayden博客的AntiForgeryToken和ValidateAntiForgeryToken属性
基本上,这些文章和建议说,为了防止CSRF攻击,任何人都应该实现以下代码:
在接受POST Http谓词的每个操作上添加[ValidateAntiForgeryToken]
(HttpPost)
(ValidateAntiForgeryToken)
SomeAction(SomeModel模型){
}
在向服务器提交数据的表单中添加<%= Html.AntiForgeryToken() %> helper
无论如何,在我的应用程序的某些部分,我做Ajax post与jQuery到服务器没有任何形式。例如,当我让用户点击图像来执行特定操作时就会发生这种情况。
假设我有一个包含活动列表的表。我在表的一列上有一个图像,说“标记活动已完成”,当用户单击该活动时,我正在做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调用的数据参数中包含helper调用?
很抱歉写了这么长时间,非常感谢你的帮助
编辑:
根据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) {
// ....
}
});
});
在这里我感觉自己像个高级的死灵法师,但这在MVC5四年后仍然是一个问题。
为了正确地处理ajax请求,需要在ajax调用时将防伪造令牌传递给服务器。将它集成到你的post数据和模型中是混乱和不必要的。将令牌作为自定义标头添加是干净且可重用的—您可以对其进行配置,这样就不必每次都记得这样做。
有一个例外- Unobtrusive ajax不需要ajax调用的特殊处理。令牌像往常一样在常规隐藏输入字段中传递。和普通POST完全一样。
_Layout.cshtml
在_layout。我有这个JavaScript块。它不将令牌写入DOM,而是使用jQuery从MVC Helper生成的隐藏输入文本中提取令牌。作为头名称的Magic字符串被定义为属性类中的常量。
<script type="text/javascript">
$(document).ready(function () {
var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
//http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative
$.ajaxSetup({
beforeSend: function (xhr) {
if (!isAbsoluteURI.test(this.url)) {
//only add header to relative URLs
xhr.setRequestHeader(
'@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME',
$('@Html.AntiForgeryToken()').val()
);
}
}
});
});
</script>
注意,在beforeSend函数中使用了单引号——呈现的输入元素使用双引号,这将破坏JavaScript文字。
客户端JavaScript
当它执行时,上面的beforeSend函数被调用,并且AntiForgeryToken被自动添加到请求头中。
$.ajax({
type: "POST",
url: "CSRFProtectedMethod",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
//victory
}
});
服务器库
需要自定义属性来处理非标准令牌。这建立在@viggity的解决方案上,但正确地处理了不显眼的ajax。这些代码可以隐藏在公共库中
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
var headerTokenValue = request.Headers[HTTP_HEADER_NAME];
// Ajax POSTs using jquery have a header set that defines the token.
// However using unobtrusive ajax the token is still submitted normally in the form.
// if the header is present then use it, else fall back to processing the form like normal
if (headerTokenValue != null)
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, headerTokenValue);
}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
}
服务器/控制器
现在只需将属性应用到Action。更好的是,你可以将属性应用到你的控制器,所有的请求都将被验证。
[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
return Json(true, JsonRequestBehavior.DenyGet);
}
我只是在我当前的项目中实现了这个实际问题。我做的所有ajax- post,需要一个认证用户。
首先,我决定钩我的jquery ajax调用,所以我不重复自己太频繁。这个javascript代码片段确保所有ajax (post)调用都会将我的请求验证令牌添加到请求中。注意:名字__RequestVerificationToken是由. net框架使用的,所以我可以利用标准的Anti-CSRF特性,如下所示。
$(document).ready(function () {
var securityToken = $('[name=__RequestVerificationToken]').val();
$('body').bind('ajaxSend', function (elm, xhr, s) {
if (s.type == 'POST' && typeof securityToken != 'undefined') {
if (s.data.length > 0) {
s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
else {
s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
}
});
});
在你的视图中,你需要令牌对上面的javascript可用,只需使用通用的HTML-Helper。基本上,您可以在任何需要的地方添加此代码。我把它放在if(Request.IsAuthenticated)语句中:
@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller
在你的控制器中简单地使用标准的ASP。Net MVC Anti-CSRF机制。我是这样做的(尽管我实际上使用了Salt)。
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
// do something
return Json(true);
}
使用Firebug或类似的工具,你可以很容易地看到你的POST请求现在有一个__RequestVerificationToken参数附加。