热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用ASP.NETCore、JavaScript和Angular防止CSRF攻击

目录介绍关于源代码CSRF示例攻击剖析保护您的Web应用程序CSRF攻击实战防伪令牌ASP.NETCore中的防伪令牌生成:手动方式令牌生成&#x

目录

介绍

关于源代码

CSRF示例

攻击剖析

保护您的Web应用程序

CSRF攻击实战

防伪令牌

ASP.NET Core中的防伪

令牌生成:手动方式

令牌生成:自动方式

令牌验证

Javascript 中的防伪

Angular中的防伪

Angular绝对路径问题

概括




  • 从Github下载源代码

介绍

跨站点请求伪造,也称为CSRF(发音为“See-Surf”)、XSRF、一键攻击和会话骑乘,是一种攻击类型,攻击者强制用户在应用程序中执行不需要的操作,而用户已登录。攻击者诱骗用户代表他们执行操作。此攻击的影响取决于用户拥有的权限级别。例如,在易受攻击的银行网站中,攻击者可以从受害者的账户中转移一定数量的资金或取得整个账户的所有权。


关于源代码

本文示例的源代码可在GitHub上通过以下链接获得:


  • GitHub - elsheimy/Elsheimy.Samples.Antiforgery: CSRF attacks samples in ASP.NET Core, Javascript and Angular

您在存储库中有五个项目:


  • 攻击样本项目,AttackSample.AttackerAppAttackSample.VulnerableApp其出示有效的CSRF攻击存在漏洞的应用程序。
  • 安全样本项目,SecureSample.SecureAppSecureSample.AttackerApp其显示出失败的CSRF攻击受保护的应用程序。
  • Angular项目,独立存在的SecureSample.AngularApp

CSRF示例

如果我们以银行网站为例,攻击者可能会诱使用户加载某些网站或链接,其中包含向银行网站发出伪造请求以转移一些资金的脚本。如果用户当前登录了银行网站,并且该网站容易受到此类攻击,则攻击者可能会成功。

例如,如果银行网站允许以下转账请求:

GET http://vulnerable-bank.com/transfer?amount=1000&to=12345


攻击者可以将他的银行帐号插入to字段,并将用户发送到一个页面,该页面包含一个脚本,可以发出上述请求或鼓励他/她点击某个链接,例如:

Read More!


或者将请求嵌入到一个假的0x0图像中:



攻击者可以将他的代码包含在用户经常访问的站点中(例如,将链接放入某些下载论坛),或者在一些社会工程的帮助下分发他的页面,例如通过电子邮件或聊天发送链接。

如果用户已经登录了银行账户,当他/她打开页面或点击虚假链接时,浏览器会自动包含目标网站COOKIEs等数据并执行伪造请求,导致转账请求成功。


攻击剖析

总之,成功的CSRF攻击包括:


  • 易受攻击的网站
  • 当前登录到该网站的用户
  • 浏览器可能包含在请求中的会话和其他用户COOKIE
  • 易于预测的请求参数
  • 用户访问有害页面或点击虚假链接,对易受攻击的网站执行伪造请求

保护您的Web应用程序

为了保护您的Web应用程序免受此类攻击,请始终:


  • 使用不可预测的参数。使攻击者难以模拟或构建对您的应用程序的请求。使用令牌的不可预测参数的示例,将很快解释。
  • 在每种情况下和每一步都严格验证。

CSRF攻击实战

在我们的代码示例中,我们有两个AttackSample项目,一个用于易受攻击的应用程序,另一个用于攻击者应用程序。在易受攻击的应用程序中,对用户进行身份验证,并创建一个COOKIE来保存用户数据:

[HttpGet]
public bool IsAuthenticated()
{return Context.Request.COOKIEs["IsAuthenticated"] == "1";
}[HttpPost]
public IActionResult Login()
{Context.Response.COOKIEs.Append("IsAuthenticated", "1");return RedirectToAction(nameof(Index), "Home");
}[HttpPost]
public IActionResult Logout()
{Context.Response.COOKIEs.Delete("IsAuthenticated");return RedirectToAction(nameof(Index), "Home");
}


该应用程序维护一个balance对象,并允许对借方和贷方操作进行易于预测的请求:

[HttpGet]
public int Balance()
{return CurrentBalance;
}[HttpPost]
public int Debit(int amount)
{CurrentBalance -= amount;return Balance();
}[HttpPost]
public int Credit(int amount)
{CurrentBalance += amount;return Balance();
}


另一方面,攻击者通过在用户单击链接时向他承诺礼物来诱使用户执行虚假请求:




用户被诱骗执行虚假请求并导致成功转移金额。


防伪令牌

保护您的网站免受此类攻击的关键是使用不可预测的请求参数。这些不可预测的参数之一是防伪令牌。

防伪令牌,也称为CSRF令牌,是由服务器端应用程序为客户端发出的后续HTTP请求生成的唯一的、秘密的、不可预测的参数。发出该请求时,服务器会根据预期值验证此参数,如果令牌丢失或无效,则拒绝该请求。

所以,基本上,以下请求:

GET http://bank.com/transfer?amount=1000&to=12345


将扩展为第三个参数:

GET http://bank.com/transfer?amount=1000&to=12345&token=32465468465468465165484654768732467655465


这个令牌是巨大的,无法猜测。服务器将仅为后续请求包含该令牌,并且每次提供页面/表单时都会生成一个新令牌。

从技术上讲,防伪令牌不是在查询字符串中发送的参数。事实上,它是一个COOKIE,表示为您在表单中生成的隐藏字段。提交表单时,此值将作为标头与请求一起包含在内。服务器代码将检查请求并验证从客户端发送的值。


ASP.NET Core中的防伪

默认情况下,新的ASP.NET Core Razor引擎将包含页面表单的防伪令牌,您只需添加相应的验证即可。尽管如此,接下来的几节将让您了解如何在您的应用程序中生成防伪令牌以及如何验证它们。


令牌生成:手动方式

有两种方法可以生成和验证防伪令牌,我们将从不方便的手动方式开始。这可以通过使用IAntiForgery服务来完成。

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Csrf
@functions {public string GenerateCsrfToken(){return Csrf.GetAndStoreTokens(Context).RequestToken;}
}


GetAndStoreTokens方法生成请求令牌并将令牌存储在响应COOKIE中。您可以使用该RequestToken属性访问生成的令牌。

生成的隐藏字段将如下所示(为清楚起见,已将标记缩写):

name="RequestVerificationToken" value="CfDJ8El14QZHDe5Dtl0m3qOu6_PbEHcKAJ5ZjSRj6iF...">


手动生成CSRF令牌的另一种更清晰的方法是使用MVC HTML帮助程序:

@Html.AntiForgeryToken()


您可以使用Chrome DevTools检查生成的COOKIE:


令牌生成:自动方式

正如我们之前所说,新的ASP.NET Core Razor引擎将始终为您生成CSRF令牌,但是,您仍然可以控制令牌生成过程。

您可以使用AddAntiforgery方法自定义 Razor 页面的令牌生成过程,该方法可以在您的Startup.ConfigureServices方法中调用的。

services.AddAntiforgery(options =>
{options.FormFieldName = "AntiForgeryFieldName";options.HeaderName = "AntiForgeryHeaderName";options.COOKIE.Name = "AntiForgeryCOOKIEName";
});


前面的代码将为具有指定名称的令牌生成一个隐藏字段,该令牌将与具有指定标头名称的请求一起发送。



默认情况下,ASP.NET core中生成的COOKIE名称为“.AspNetCore.Antiforgery.,字段名称为“__RequestVerificationToken”,头部名称为“RequestVerificationToken”


令牌验证

现在是下一步,令牌验证。让我们以正常的、不舒服的方式开始。在您的目标操作中,您可以使用以下代码进行令牌验证:

private Microsoft.AspNetCore.Antiforgery.IAntiforgery Csrf { get; set; }public ApiController(Microsoft.AspNetCore.Antiforgery.IAntiforgery csrf)
{this.Csrf = csrf;
}private async Task ValidateAntiForgeryToken()
{try{await Csrf.ValidateRequestAsync(this.HttpContext);return true;}catch (Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException){return false;}
}[HttpPost]
public async Task> Debit(int amount)
{if (false == await ValidateAntiForgeryToken())return BadRequest();// action logic here
}


在前面的代码中,我们首先定义了我们的IAntiforgery服务。此服务允许您使用在令牌无效时引发AntiforgeryValidationException异常的ValidateRequestAsync方法来验证给定的请求。我们在我们的Debit方法中首先调用了这个函数,并为无效令牌返回了400 Bad Request响应。

验证CSRF令牌的另一种更清晰的方法是使用以下ValidateAntiForgeryToken属性:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task> Debit(int amount)


上述代码将执行与手动IAntiforgery服务代码相同的功能。

现在,当我们运行我们的应用程序时,我们可以看到不同之处。该应用程序已针对CSRF攻击进行保护,攻击者无法向您的应用程序执行请求。

值得一提的是,ValidateAntiForgeryToken可以应用于控制器类,并将导致所有端点上的CSRF验证。我们还有一些使用ValidateAntiForgeryToken属性的替代方法:


  • AutoValidateAntiForgeryToken属性:将自动验证端点除了所有HTTP方法GET,HEAD,OPTIONSTRACE
  • IgnoreAntiforgeryToken属性:如果父类用ValidateantiForgeryToken或修饰,则将忽略验证中的方法AutoValidateAntiForgeryToken

Javascript 中的防伪

让我们再举一个例子。假设您使用Javascript访问API,并使用以下代码调用该credit方法:

function request(url) {let url = location.origin + "/api/credit?amount=10";var request = {};request.url = url;request.type = 'POST';request.success = function (balance) {$('#balance')[0].innerText = balance;};request.error = function (xhr) {alert(`${xhr.status} ${xhr.statusText}`);};$.ajax(request);
}


当防伪验证运行时,您将收到400 bad request错误,这是意料之中的,因为ASP.NET Core引擎找不到CSRF令牌标头。

为此,我们必须手动将我们的CSRF令牌添加到我们的请求标头列表中。对我们的代码稍作改动即可解决问题:

function request(url) {let url = location.origin + "/api/debit?amount=10";var request = {};request.url = url;request.type = 'POST';request.headers = {'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val()};request.success = function (balance) {$('#balance')[0].innerText = balance;};request.error = function (xhr) {alert(`${xhr.status} ${xhr.statusText}`);};$.ajax(request);
}


正如我们之前所说,CSRF令牌的默认标头名称是RequestVerificationToken。如果您出于任何原因更改了默认标头名称:

services.AddAntiforgery(options =>
{options.HeaderName = "AntiForgeryHeaderName";
});


然后,您必须更改Javascript代码中的值:

request.headers = {'AntiForgeryHeaderName': $('input[name="__RequestVerificationToken"]').val()
};



Angular中的防伪

通常,当从Angular应用程序访问受CSRF保护的端点时,如果您没有指定CSRF标头,您将收到400个错误的请求

要处理此问题,您必须了解以下内容:


  • 只有当它作为COOKIE存储在Angular的专用名称下时,Angular才会识别CSRF令牌,即XSRF-TOKEN
  • Angular将始终将COOKIE令牌作为专用名称X-XSRF-TOKEN下的标头发送。
  • 您的应用程序必须能够在Angular的专用名称下生成CSRF COOKIE,并在Angular的专用名称下验证CSRF标头。

让我们看看我们如何做到这一点:

public void Configure
(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
{app.Use((context, next) =>{// return current accessed pathstring path = context.Request.Path.Value;if (path.IndexOf("/api/", StringComparison.OrdinalIgnoreCase) != -1){var tokens = antiforgery.GetAndStoreTokens(context);context.Response.COOKIEs.Append("XSRF-TOKEN", tokens.RequestToken,new COOKIEOptions() { HttpOnly = false });}return next();});
}


代码相当简单,它执行以下操作:


  • 它首先定义一个将为每个请求执行的中间件。该中间件将负责生成具有专用名称的CSRF COOKIE
  • 在这个中间件中,它检查请求的路径。您不需要为所有请求生成COOKIE,您只需要为API目标请求生成COOKIE。从技术上讲,您需要为针对我们的API控制器/api/ ”的请求生成此 COOKIE
  • 接下来,代码使用该IAntiforgery服务生成CSRF令牌并将其存储在使用该GetAndStoreTokens方法的COOKIE中。我们之前在手动令牌生成部分中使用过这种机制。除非您使用AddForgery方法(前面提到)更改默认COOKIE名称,否则生成的令牌的默认名称将以.AspNetCore.Antiforgery开头,正如我们之前所说。
  • 最后,该代码读取生成的令牌并将其存储在COOKIE中以用于发送请求。它使用专用的Angular COOKIE名称XSRF-TOKEN

下一步是配置生成的应用程序以读取正确的标头。正如我们之前所说,我们必须保留默认的Angular CSRF标头名称X-XSRF-TOKEN

services.AddAntiforgery(opts =>
{opts.HeaderName = "X-XSRF-TOKEN";});


现在,运行应用程序并查看charm。我们不再收到400 bad request错误。并且在使用 Chrome DevToolsFiddler调查请求时,我们可以清楚地看到生成的COOKIE和标头名称。


Angular绝对路径问题

如果请求的路径是相对的,上面的代码将像charm一样工作:

debit(amount: number): Observable {// relative pathlet url = `/api/debit?amount=${amount}`;return this.request(url);
}request(url: string): Observable {let result: number;return this.http.post(url, { });
}


但是,当请求的路径是绝对路径时,即使是同一主机,Angular也不够聪明,无法在请求中包含CSRF令牌。您必须手动将其包含在您的请求中。例如,以下代码将不起作用:

credit(amount: number): Observable {// absolute pathlet url = this.baseUrl + `api/credit?amount=${amount}`;return this.request(url);
}


这种情况的解决方法是手动将header添加到请求中,或者使用HTTP拦截器自动将其添加到所有请求中。让我们看看如何定义我们的拦截器。我们将从拦截器类本身开始。

import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpXsrfTokenExtractor } from "@angular/common/http";
import { HttpEvent, HttpHandler, HttpRequest } from "@angular/common/http";
import { Observable } from "rxjs";@Injectable()
export class XsrfInterceptor implements HttpInterceptor {constructor(private xsrfTokenExtractor: HttpXsrfTokenExtractor) {}intercept(req: HttpRequest, next: HttpHandler): Observable> {// load tokenlet xsrfToken = this.xsrfTokenExtractor.getToken();if (xsrfToken != null) {// create a copy of the request and// append the XSRF token to the headers listconst authorizedRequest = req.clone({withCredentials: true,headers: req.headers.set('X-XSRF-TOKEN', xsrfToken)});return next.handle(authorizedRequest);} else {Return next.handle(req);}}
}


上面的代码只是使用HttpXsrfTokenExtractor处理从COOKIE中提取令牌的服务来提取令牌。然后它复制当前请求并使用专用名称X-XSRF-TOKEN附加CSRF标头。最后,通过管道将请求传递给下一个处理程序。

要使用该HttpXsrfTokenExtractor服务,您需要在应用程序导入中包含其模块。

imports: [HttpClientModule,
],


最后,您必须将拦截器包含在应用程序的可注入对象中。

providers: [{ provide: HTTP_INTERCEPTORS, useClass: XsrfInterceptor, multi: true }
],


现在您可以运行该应用程序并查看它如何针对所有请求顺利运行。

值得一提的是,如果您的Angular应用程序包含在Razor CSHTML文件中,您可以使用常规方式简单地生成CSRF令牌:

@Html.AntiForgeryToken()


Angular代码中,您可以使用jQuery样式来获取令牌的值,并使用如下代码将其包含在您的请求中:

declare var $: any;const httpOptions = {headers: new HttpHeaders({'X-XSRF-Token': $('input[name=__RequestVerificationToken]').val()})};
this.http.post(url, httpOptions);



概括

到本文结束时,我认为您已经全面了解CSRF攻击的工作原理以及如何保护您的应用免受这些攻击。

同样,示例的源代码可在GitHub上通过以下链接获得:


  • GitHub - elsheimy/Elsheimy.Samples.Antiforgery: CSRF attacks samples in ASP.NET Core, Javascript and Angular

您在存储库中有五个项目:


  • 攻击样本项目,AttackSample.AttackerAppAttackSample.VulnerableApp其出示有效的CSRF攻击存在漏洞的应用程序。
  • 安全样本项目,SecureSample.SecureAppSecureSample.AttackerApp其显示出失败的CSRF攻击受保护的应用程序。
  • Angular 项目,独立存在的SecureSample.AngularApp

https://www.codeproject.com/Articles/5297793/Preventing-CSRF-Attacks-using-ASP-NET-Core-JavaScr


推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • 【爬虫】关于企业信用信息公示系统加速乐最新反爬虫机制
    ( ̄▽ ̄)~又得半夜修仙了,作为一个爬虫小白,花了3天时间写好的程序,才跑了一个月目标网站就更新了,是有点悲催,还是要只有一天的时间重构。升级后网站的层次结构并没有太多变化,表面上 ... [详细]
  • XMLhttpREquest_Ajax技术总结之XmlHttpRequest
    Ajax1、 什么是ajax   ... [详细]
  • 我正在尝试使用scrapycrallsingle运行完美运行的scrapy蜘蛛,但我无法在python脚本中运行它.主要问题是从不执行SingleBlogSpider.parse方 ... [详细]
  • 一.常见基于身份识别进行反爬1通过headers字段来反爬headers中有很多字段,这些字段都有可能会被对方服务器拿过来进行判断是否为爬虫1.1通过headers中的User-A ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
  • 找到JDK下载URL当然去官网找了。目前最新的1.8的下载URL(RPM)如下:http:download.oracle.comotn-pubjavajdk8u161-b122f3 ... [详细]
author-avatar
向陽阿莫_545
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有