什么是反伪造攻击?
跨站点请求伪造(也称为XSRF或CSRF,发音为see-surf)是对Web托管应用程序的攻击,因为恶意网站可能会影响客户端浏览器和浏览器信任网站之间的交互。这种攻击是完全有可能的,因为Web浏览器会自动在每一个请求中发送某些身份验证令牌到请求网站。这种攻击形式也被称为 一键式攻击 或 会话控制 ,因为攻击利用了用户以前认证的会话。
CSRF攻击的示例:
(1)用户登录 www.example.com,使用表单身份验证。
(2)服务器对用户进行身份验证,并作出包含身份验证Cookie的响应。
(3)用户访问恶意网站。
恶意网站包含类似于以下内容的HTML表单:
<h1>You Are a Winner!</h1> <form action="http://example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click Me"/> </form>
请注意,表单的Action属性将请求发送到易受攻击的网站,而不是恶意网站。这是CSRF的“跨站点”部分。
(4)用户点击提交按钮,浏览器会自动包含请求站点(在这种情况下为易受攻击的站点)的认证Cookie。
(5)请求在拥有用户身份验证上下文的服务端运行,并且可以执行允许经过身份验证用户执行的任何操作。
此示例需要用户单击表单按钮,恶意页面也可以通过以下方式:
- 自动运行提交表单的脚本。
- 通过AJAX请求发送表单提交。
- 通过CSS隐藏的表单。
使用SSL不能阻止CSRF攻击,恶意网站可以发送https://请求。
针对GET请求站点的攻击,可以使用Image元素来执行(这种形式的攻击在允许图片的论坛网站上很常见)。使用GET请求更改应用程序状态更容易受到恶意攻击。
因为浏览器将所有相关的Cookie发送到目标网站,所以可以针对使用Cookie进行身份验证的网站进行CSRF攻击。然而,CSRF攻击并不仅限于利用Cookie,例如,Basic和Digest身份验证也很脆弱。用户使用Basic或Digest身份验证登录后,浏览器将自动发送凭据,直到会话(Session)结束。
注意:在这本文中,Session是指用户进行身份验证的客户端会话。它与服务器端会话或Session中间件无关。
用户可以通过以下方式防范CSRF漏洞:
- 网站使用完毕后,注销会话。
- 定期清理浏览器的Cookie。
然而,CSRF漏洞根本上是Web应用程序的问题,而不是依靠用户来解决。
ASP.NET Core MVC是如何处理CSRF的?
警告:
ASP.NET Core使用 ASP.NET Core data protection stack 来实现防请求伪造。如果在服务器集群中必配置 ASP.NET Core Data Protection,有关详细信息,请参阅 Configuring data protection。
在ASP.NET Core MVC 2.0中,FormTagHelper为HTML表单元素注入防伪造令牌。例如,Razor文件中的以下标记将自动生成防伪令牌:
<form method="post"> <!-- form markup --> </form>
在以下情况为HTML格式元素自动生成防伪令牌:
- 该form标签包含method="post"属性
- action属性为空( action="") 或者
- 未提供action属性(<form method="post">)。
您可以通过以下方式禁用自动生成HTML表单元素的防伪令牌:
- 明确禁止asp-antiforgery,例如
<form method="post" asp-antiforgery="false"> </form>
- 通过使用标签帮助器! 禁用语法,从标签帮助器转化为表单元素。
<!form method="post"> </!form>
- 在视图中移除FormTagHelper,您可以在Razor视图中添加以下指令移除FormTagHelper:
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
提示:
Razor页面会自动受到XSRF/CSRF的保护。您不必编写任何其他代码,有关详细信息,请参阅XSRF/CSRF和Razor页面。
防御CSRF攻击的最常见方法是令牌同步模式(STP)。STP是当用户请求表单数据页面时使用的技术。服务器将与当前用户的标识相关联的令牌发送给客户端。客户端将令牌发回服务器进行验证。如果服务器接收到与验证用户身份不匹配的令牌,则该请求将被拒绝。令牌是唯一的,并且是不可预测的。令牌也可用于确保一系列请求的正确顺序(确保页面1在第2页之前,页面2在第3页之前)。ASP.NET Core MVC模板中的所有表单都会生成防伪令牌,以下两个示例演示在视图逻辑中生成防伪令牌:
<form asp-controller="Manage" asp-action="ChangePassword" method="post"> </form> @using (Html.BeginForm("ChangePassword", "Manage")) { }
您可以在不使用HTML标签助手的情况下,向<form>元素显式添加防伪令牌@Html.AntiForgeryToken:
<form action="/" method="post"> @Html.AntiForgeryToken() </form>
在前面的例子中,ASP.NET Core将添加一个隐藏的表单字段,类似于以下内容:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkSldwD9CpLRyOtm6FiJB1Jr_F3FQJQDvhlHoLNJJrLA6zaMUmhjMsisu2D2tFkAiYgyWQawJk9vNm36sYP1esHOtamBEPvSk1_x--Sg8Ey2a-d9CV2zHVWIN9MVhvKHOSyKqdZFlYDVd69XYx-rOWPw3ilHGLN6K0Km-1p83jZzF0E4WU5OGg5ns2-m9Yw" />
ASP.NET Core 包括三个过滤器用于防伪令牌的运行:ValidateAntiForgeryToken、AutoValidateAntiforgeryToken和 IgnoreAntiforgeryToken。
ValidateAntiForgeryToken
ValidateAntiForgeryToken是一个可应用于单个Action、控制器或全局的操作过滤器。请求必须包含一个有效的令牌,否则对具有该过滤器Action的请求将被阻止。
[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特性标记的Action方法需要一个令牌,包括HTTP GET请求。如果您全局使用,您可以使用IgnoreAntiforgeryToken特性来覆盖它。
AutoValidateAntiforgeryToken
ASP.NET Core应用程序通常不会为HTTP安全方式(GET,HEAD,OPTIONS和TRACE)生成防伪令牌,而不是在全局范围内使用ValidateAntiForgeryToken特性,然后用IgnoreAntiforgeryToken特性覆盖它,您可以使用AutoValidateAntiforgeryToken特性。该特性与ValidateAntiForgeryToken特性相似,但对以下HTTP请求方式不需要请求令牌:
- GET
- HEAD
- OPTIONS
- TRACE
我们建议您在非API场景中广泛使用AutoValidateAntiforgeryToken。这确保您的POST Action 默认受保护。另一种方式是在默认情况下忽略反伪造令牌,除非在个别Action方法标记了ValidateAntiForgeryToken特性,不过在这种情况下,POST Action方法有可能不受保护,使您的应用程序容易受到CSRF攻击。即使匿名的POST请求也应该发送防伪令牌。
注意:API没有自动机制来发送非Cookie的令牌;您的实现可能取决于您的客户端代码的实现。
一些例子如下所示。
示例(控制器级别):
[Authorize] [AutoValidateAntiforgeryToken] public class ManageController : Controller {
示例(全局)
services.AddMvc(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
IgnoreAntiforgeryToken
IgnoreAntiforgeryToken过滤器用于取消已经使用防伪标记的Action(或控制器)的需求。应用时,此过滤器将覆盖在更高级别(全局或控制器)上指定的过滤器ValidateAntiForgeryToken和/或AutoValidateAntiforgeryToken过滤器。
[Authorize] [AutoValidateAntiforgeryToken] public class ManageController : Controller { [HttpPost] [IgnoreAntiforgeryToken] public async Task<IActionResult> DoSomethingSafe(SomeViewModel model) { // no antiforgery token required } }