问题描述
我有一个Web应用程序,它使用ASP.NET核心(3.1)后端和角度前端(8.2.11)。它使用ASP.NET身份框架进行用户身份验证。它将身份验证令牌存储在本地存储中,以用作请求中身份验证头。Sense控制器中的一切都在运行,只有当用户登录时才能访问终结点,如果注销,则直接在浏览器中键入终结点将被拒绝。
我仍然不确定这样的设置是否可以防止跨站点请求伪造(XSRF/CSRF)攻击。我知道使用Cookie存储身份验证令牌容易受到CSRF的影响,我在一些端点上尝试了一下[ValidateAntiForgeryToken]
属性,当然它破坏了这些端点。我知道在剃刀页面中,一张表格会自动注入防伪令牌。那么,我需要在我的棱角前端设置它吗?如果是,又是如何做到的?(我在网上搜索了一下,说明到处都是,相当混乱,没有明确的共识)。推荐答案
第1步
将一个中间件添加到您的中间件管道中,该中间件将生成一个AntiforgeryToken,并将该令牌嵌入到一个附加到响应的非纯http cookie中:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAntiforgery(options => {
options.HeaderName = "X-XSRF-TOKEN";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
{
...;
app.Use((context, next) => {
var tokens = antiforgery.GetAndStoreTokens(httpContext);
httpContext.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { Path = "/", HttpOnly = false });
});
}
}
我为此创建了a little package,其中包含此中间件。
第2步
配置您的ANGLE应用程序通过Java脚本读取非http-only cookie(XSRF-TOKEN
)的值,并将该值作为HttpClient
发送的请求的X-XSRF-TOKEN
头传递:
@NgModule({
declarations: [...],
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN'
}),
...
],
providers: [...],
bootstrap: [AppComponent]
})
export class AppModule { }
第3步
现在您可以使用[ValidateAntiforgeryToken]
属性:
[ApiController]
[Route("web/v1/[controller]")]
public class PersonController : Controller
{
private IPersonService personService;
public PersonController(IPersonService personService)
{
this.personService = personService;
}
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public async Task<ActionResult<Person>> Post([FromBody] Person person)
{
var new_person = await personService.InsertPerson(person);
return Ok(new_person);
}
}
第4步
确保您发送的请求具有以下类型的urlas stated here:
/my/url
//example.com/my/url
错误的URL:
https://example.com/my/url
注意:
我使用身份Cookie身份验证:
services.AddAuthentication(/* No default authentication scheme here*/)
由于ASP.NET CoreAuthentication
中间件只处理XSRF-TOKEN
头,而不是X-XSRF-TOKEN
Cookie,因此您不再容易受到跨站点请求伪造的影响。
剧透
您会注意到,在登录/注销之后,发送的第一个Web请求仍然会被XSRF保护阻止。这是因为身份在Web请求的生存期内不会更改。因此,当发送Login
Web请求时,响应将附加一个带有CSRF令牌的cookie。但此令牌仍使用您尚未登录时的身份生成。
与发送Logout
Web请求相同,响应将包含一个带有CSRF令牌的Cookie,就像您仍在登录一样。
要解决这个问题,您只需在每次登录/注销时发送另一个不做任何事情的Web请求。在此请求期间,您将再次拥有正确的身份以生成CSRF令牌。
logoutClicked() {
this.accountService.logout().then(() => {
this.accountService.csrfRefresh().then(() => {
this.activeUser = null;
});
}).catch((error) => {
console.error('Could not logout', error);
});
}
登录相同
this.accountService.login(this.email, this.password).then((loginResult) => {
this.accountService.csrfRefresh().then(() => {
switch (loginResult.status) {
case LoginStatus.success:
this.router.navigateByUrl(this.returnUrl);
this.loginComplete.next(loginResult.user);
break;
default:
this.loginResult = loginResult;
break;
}
});
});
csrfRefresh
方法的内容
public csrfRefresh() {
return this.httpClient.post(`${this.baseUrl}/web/Account/csrf-refresh`, {}).toPromise();
}
服务器端
[HttpPost("csrf-refresh")]
public async Task<ActionResult> RefreshCsrfToken()
{
// Just an empty method that returns a new cookie with a new CSRF token.
// Call this method when the user has signed in/out.
await Task.Delay(5);
return Ok();
}
This is where I login the user in my own app
这篇关于根据CSRF攻击,ASP.NET核心角度Web应用程序中的ValiateAntiForgeryToken终结点属性用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!