什么是跨站请求伪造(XSRF/CSRF)
在继续之前如果不给你讲一下什么是跨站请求伪造(XSRF/CSRF)的话可能你会很懵逼,我为什么要了解这个,不处理又有什么问题呢?
CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
CSRF在 2007 年的时候曾被列为互联网 20 大安全隐患之一。其他安全隐患,比如 SQL 脚本注入,跨站域脚本攻击等在近年来已经逐渐为众人熟知,很多网站也都针对他们进行了防御。然而,对于大多数人来说,CSRF 却依然是一个陌生的概念。即便是大名鼎鼎的 Gmail, 在 2007 年底也存在着 CSRF 漏洞,从而被黑客攻击而使 Gmail 的用户造成巨大的损失。
跨站请求伪造(XSRF/CSRF)的场景
这里为了加深大家对“跨站请求伪造(XSRF/CSRF)”的理解可以看如下所示的图:
如上图所示:
-
用户浏览位于目标服务器 A 的网站。并通过登录验证。
-
获取到 cookie_session_id,保存到浏览器 cookie 中。
-
在未登出服务器 A ,并在 session_id 失效前用户浏览位于 hacked server B 上的网站。ASP.NET Core MVC是如何处理跨站请求伪造(XSRF/CSRF)的?
ASP.NET Core MVC是如何处理跨站请求伪造(XSRF/CSRF)的?
[ValidateAntiForgeryToken]、[AutoValidateAntiforgeryToken]、[IgnoreAntiforgeryToken]
ValidateAntiForgeryToken实质上是一个过滤器,可应用到单个操作,控制器或全局范围内。除了具有IgnoreAntiforgeryToken
属性的操作,否则所有应用了这个属性的Action都会进行防伪验证。如下所示:
C#复制
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
ManageMessageId? message = ManageMessageId.Error;
var user = await GetCurrentUserAsync();
if (user != null)
{
var result =
await _userManager.RemoveLoginAsync(
user, account.LoginProvider, account.ProviderKey);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
message = ManageMessageId.RemoveLoginSuccess;
}
}
return RedirectToAction(nameof(ManageLogins), new { Message = message });
}
ValidateAntiForgeryToken
属性所修饰的操作方法包括 HTTP GET 都需要一个Token进行验证。 如果ValidateAntiForgeryToken
特性应用于应用程序的控制器上,则可以应用IgnoreAntiforgeryToken
来对它进行重载以便忽略此验证过程。
<script>
function btnSubmit() {
$.ajax({
type: "Post",
url: "/manager/menuedit",
data: {__RequestVerificationToken: $("input[name='__RequestVerificationToken']").val()},
headers: {
"X-CSRF-TOKEN": '@GetAntiXsrfRequestToken()'
},
dataType: "html",
success: function (ret) {
alert(JSON.stringify(ret));
},
error: function (err, scnd) {
alert(err.statusText);
}
});
}
</script>
<form>
@Html.AntiForgeryToken()
<input type="button" onclick="btnSubmit()" value="提交 " />
</form>