当前位置: 首页 > 知识库问答 >
问题:

角度对Asp。Net WebApi,在服务器上实现CSRF

卢开济
2023-03-14

我在ngular.js中实现一个网站,它击中了ASP. NET WebAPI后端。

有棱角的js具有一些内置功能,有助于防止csrf。在每个http请求上,它将查找名为“XSRF-TOKEN”的cookie,并将其作为名为“X-XSRF-TOKEN”的标头提交。

这依赖于网络服务器能够在验证用户后设置XSRF-TOKEN cookie,然后检查传入请求的X-XSRF-TOKEN标头。

文件说明:

为了利用这一点,您的服务器需要在第一个HTTP GET请求上在名为XSRF-token的JavaScript可读会话cookie中设置令牌。在后续的非GET请求中,服务器可以验证cookie是否与X-XSRF-TOKEN HTTP头匹配,从而确保只有在您的域上运行的JavaScript才能读取令牌。令牌对于每个用户都必须是唯一的,并且必须能够被服务器验证(以防止JavaScript生成自己的令牌)。我们建议令牌是站点身份验证cookie的摘要,带有salt,以增加安全性。

对于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;
        }
    }
}

然后我在我的授权控制器中有以下方法,我在调用Forms身份验证后调用它。设置Cookie():

    // 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()
    {
        var authCookie = HttpContext.Current.Response.Cookies.Get(".ASPXAUTH");
        Debug.Assert(authCookie != null, "authCookie != null");
        var csrfToken = new CsrfTokenHelper().GenerateCsrfTokenFromAuthToken(authCookie.Value);
        var csrfCookie = new HttpCookie("XSRF-TOKEN", csrfToken) {HttpOnly = false};
        HttpContext.Current.Response.Cookies.Add(csrfCookie);
    }

然后我有一个自定义属性,我可以将其添加到控制器中,使它们检查csrf头:

public class CheckCsrfHeaderAttribute : AuthorizeAttribute
{
    //  http://stackoverflow.com/questions/11725988/problems-implementing-validatingantiforgerytoken-attribute-for-web-api-with-mvc
    protected override bool IsAuthorized(HttpActionContext context)
    {
        // get auth token from cookie
        var authCookie = HttpContext.Current.Request.Cookies[".ASPXAUTH"];
        if (authCookie == null) return false;
        var authToken = authCookie.Value;

        // get csrf token from header
        var csrfToken = context.Request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault();
        if (String.IsNullOrEmpty(csrfToken)) return false;

        // Verify that csrf token was generated from auth token
        // Since the csrf token should have gone out as a cookie, only our site should have been able to get it (via javascript) and return it in a header. 
        // This proves that our site made the request.
        return new CsrfTokenHelper().DoesCsrfTokenMatchAuthToken(csrfToken, authToken);
    }
}

最后,我在用户注销时清除Csrf令牌:

HttpContext.Current.Response.Cookies.Remove("XSRF-TOKEN");

有人能发现这种方法有什么明显(或不太明显)的问题吗?

共有3个答案

何安宜
2023-03-14

此解决方案不安全,因为只要认证cookie有效,CSRF攻击仍然是可能的。当攻击者让您通过另一个站点执行请求时,身份验证和xsrf cookie都将被发送到服务器,因此在用户进行“硬”注销之前,您仍然容易受到攻击。

每个请求或会话都应该有自己独特的令牌,以真正防止CRSF攻击。但最好的解决方案可能不是使用基于cookie的身份验证,而是使用基于令牌的身份验证,如OAuth。这可以防止其他网站使用您的cookie执行不需要的请求,因为令牌用于http头而不是cookie。http头不会自动发送。

  1. 使用ASP. NETWeb API 2、Owin和标识进行基于令牌的身份验证
  2. AngularJS令牌身份验证使用ASP. NET Web API 2,Owin和标识

这些优秀的博客文章包含了如何为WebAPI实现OAuth的信息。博客文章还包含了如何将其与AngularJS集成的大量信息。

另一种解决方案可能是禁用CORS,只接受来自白名单域的传入请求。然而,这对于非网站应用程序不起作用,例如移动和/或桌面客户端。其次,一旦你的网站容易受到XSS攻击,攻击者仍然能够伪造你的请求。

葛越泽
2023-03-14

我认为你的代码有缺陷。防止CSRF的整个想法是在每个请求上防止一个唯一的令牌,而不是在每个会话上。如果防伪令牌是会话持久化值,则仍然可以执行CSRF。您需要在每个请求上提供唯一的令牌。。。

甘永春
2023-03-14

您的代码似乎很好。唯一的问题是,你不需要你的大部分代码作为web。api在asp的“顶部”运行。net mvc,后者内置了对防伪令牌的支持。

在评论中,dbrunning和ccorrin表达了这样的担忧:只有在使用MVC html帮助程序时,才能使用内置的反伪造令牌。这不是真的。助手可以公开基于会话的令牌对,您可以对它们进行相互验证。详情见下文。

更新:

从AntiForgery可以使用两种方法:

>

防伪。验证(cookieToken,formToken)验证令牌对是否有效

您完全可以重新利用这两种方法,使用formToken作为headerToken,使用cookieToken作为实际cookieToken。然后只需在属性中对这两个属性调用validate。

另一个解决方案是使用JWT(检查eg Membership重新启动实现)

此链接显示如何在ajax中使用内置防伪令牌:

<script>
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }

    $.ajax("api/values", {
        type: "post",
        contentType: "application/json",
        data: {  }, // JSON data goes here
        dataType: "json",
        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        }
    });
</script>


void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}

还要看看这个问题AngularJS找不到XSRF-TOKEN cookie

 类似资料:
  • 我正在使用Telerik平台开发一个移动应用程序。应用程序使用的服务是ASP。托管在Azure上的NETWebAPI RESTful服务。我想通过添加服务总线来增强应用程序的弹性,并且一直在关注Azure服务总线,这似乎就是我所寻找的。 这对我来说相当新鲜,我有几个问题。 Azure服务总线可以用于返回数据的RESTful服务吗? 对于简单的RESTful服务,是Azure服务总线还是Azure存

  • 问题内容: 我正在Angular.js中实现一个网站,该网站访问了ASP.NET WebAPI后端。 Angular.js具有一些内置功能,可帮助进行反csrf保护。在每个http请求上,它将查找名为“ XSRF-TOKEN”的cookie,并将其作为名为“ X-XSRF-TOKEN”的标头提交。 这取决于Web服务器能够在验证用户身份之后设置XSRF-TOKEN cookie,然后检查X-XSR

  • 问题内容: 我已经看到angular.factory()和angular.service()都用于声明服务;但是,我在官方文档中找不到 任何地方。 两种方法有什么区别? 应该使用哪个(假设他们做不同的事情)? 问题答案: 直到我以这种方式对自己说: 服务 :您编写的 函数 将是 新的 -ed: Factory* :将 调用 您编写的 函数 (构造函数): * 您可以根据自己的意愿进行操作,但是有一

  • 在之前的几篇教程中,我们讲的是如何查询和Mutation操作,这些都是在客户端那边所进行的,那么服务器这边是如何处理这些请求的呢?这就是这篇教程所要说的东西了. 准备工作 克隆库: git clone https://github.com/zhouyuexie/learn-graphql 安装依赖: cd learn-graphql && npm install cd learn-graphql

  • 问题内容: 我在我的角度应用程序中创建了工厂/服务。 我想在浏览器中调试它。有没有一种方法可以访问其实例并检查其函数和变量的值是什么? 角度范围可以使用 是否有类似的方式访问工厂? 问题答案: 我相信您可以使用以下方式: 并且由于angularjs服务是 单例的 ,因此在任何 angular.element 上执行此操作都将始终返回相同的服务实例/对象。

  • 问题内容: 我是一个有角的新手,正在构建一个应用程序,让我感到困惑的是,有几种方法定义了服务,我从此链接中了解了更多:如何定义服务, 然后似乎没有太大的区别定义服务的方式。 但我只是注意到我认为是不同的一个不同之处: 看到我从这里得到的这项服务http://jsfiddle.net/2by3X/5/ 如果我使用如下所示的“工厂”定义此服务,则一个功能不能调用该服务的其他功能。 我将在浏览器控制台中