我正在Angular.js中实现一个网站,它正在攻击ASP.NET WebAPI后端.
Angular.js具有一些内置功能,可以帮助防止csrf.在每个http请求中,它将查找名为"XSRF-TOKEN"的cookie并将其作为名为"X-XSRF-TOKEN"的标头提交.
这依赖于Web服务器能够在对用户进行身份验证之后设置XSRF-TOKEN cookie,然后检查X-XSRF-TOKEN标头以获取传入请求.
该角文档状态:
要利用这一点,您的服务器需要在第一个HTTP GET请求中在名为XSRF-TOKEN的JavaScript可读会话cookie中设置令牌.在后续的非GET请求中,服务器可以验证cookie是否与X-XSRF-TOKEN HTTP标头匹配,因此请确保只有您域上运行的JavaScript才能读取令牌.令牌对于每个用户必须是唯一的,并且必须由服务器验证(以防止JavaScript组成自己的令牌).我们建议令牌是您网站的身份验证cookie的摘要,以增加安全性.
我找不到ASP.NET WebAPI的任何好例子,所以我在各种来源的帮助下推出了自己的例子.我的问题是 - 任何人都可以看到代码有什么问题吗?
首先我定义了一个简单的帮助器类:
public class CsrfTokenHelper
{
const string ConstantSalt = "<ARandomString>";
public string GenerateCsrfTokenFromAuthToken(string authToken)
{
return GenerateCookieFriendlyHash(authToken);
}
public bool DoesCsrfTokenMatchAuthToken(string csrfToken, string authToken)
{
return csrfToken == GenerateCookieFriendlyHash(authToken);
}
private static string GenerateCookieFriendlyHash(string authToken)
{
using (var sha = SHA256.Create())
{
var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(authToken + ConstantSalt));
var cookieFriendlyHash = HttpServerUtility.UrlTokenEncode(computedHash);
return cookieFriendlyHash;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在授权控制器中使用以下方法,并在调用FormsAuthentication.SetAuthCookie()后调用它:
// http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks
// http://docs.angularjs.org/api/ng.$http
private void SetCsrfCookie() …Run Code Online (Sandbox Code Playgroud) 我们有一些现有的MVC Web服务,从Web页面称为AJAX样式.这些服务使用ValidateAntiForgeryToken属性来帮助防止请求伪造.
我们希望将这些服务迁移到Web API,但似乎没有等效的防伪功能.
我错过了什么吗?是否有不同的方法来解决使用Web API的请求伪造?
我有一个MVC视图应该是iFramed.它的几个实例可能是iFramed在同一个主页中.在我看来,我有这个:
@Html.AntiForgeryToken()
Run Code Online (Sandbox Code Playgroud)
我用来尝试确保调用web api只来自此页面.我的主机页面可能如下所示:
<iframe src="http://myserver.com/myview?someparameters=0000"></iframe>
<iframe src="http://myserver.com/myview?someparameters=0001"></iframe>
<iframe src="http://myserver.com/myview?someparameters=0002"></iframe>
Run Code Online (Sandbox Code Playgroud)
在我看来,我抓住令牌并在标题中提交它,以便我可以在我的API中检查它:
var headers = actionContext.Request.Headers;
var headerToken = headers.Contains("__RequestVerificationToken") ? headers.GetValues("__RequestVerificationToken").FirstOrDefault() : null;
var cookie = headers.GetCookies("__RequestVerificationToken").FirstOrDefault()?["__RequestVerificationToken"]?.Value;
AntiForgery.Validate(cookie,headerToken);
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,在我的主机页面中,所有三个视图都是并行加载的.因此,他们都在隐藏字段中获取自己的随机令牌并尝试设置cookie.但是,虽然可以有三个独立的独立隐藏输入令牌,但只能有一个cookie.因此,在三个请求中,两个将失败,一个将成功.重新加载页面将使所有三个都重新工作,大概是因为它们在这一点上都获得了相同的防伪标记(因为它属于会话 - 如果我理解正确的话).
那我怎么能避免这个呢?我怎样才能确保他们都获得相同的标记?
当我无法保证客户端将使用哪个平台时,我[Authorize]在严格(即View较少)的ASP.NET Core WebAPI项目中使用注释时遇到了问题.也就是说,应用程序需要是一个真正的API,不需要特定的平台来访问.
注意:当我说"严格的WebAPI"时,我的项目实际上是作为由...生成的MVC项目开始的.
Run Code Online (Sandbox Code Playgroud)dotnet new mvc --auth Individual...我立即从中删除了所有视图等,并更改了路由首选项以匹配WebAPI约定.
当我通过AJAX访问标准登录功能(在下面的粘贴中剥离到基本要素)时,我获得了一个JSON有效负载并返回了一个cookie.
[HttpPost("apiTest")]
[AllowAnonymous]
public async Task<IActionResult> ApiLoginTest([FromBody] LoginViewModel model, string returnUrl = null)
{
object ret = new { Error = "Generic Error" };
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
ret = new { Success = true };
else
ret = new { Error = "Invalid login attempt" };
}
return new ObjectResult(ret);
}
Run Code Online (Sandbox Code Playgroud)
成功时,返回类似于以下内容的cookie:
.AspNetCore.Identity.Application=CfDJ8Ge9E-[many characters …Run Code Online (Sandbox Code Playgroud) asp.net-mvc ×2
c# ×2
ajax ×1
angularjs ×1
asp.net ×1
cookies ×1
csrf ×1
iframe ×1
javascript ×1