Programing

Asp.Net WebApi에 대한 Angular, 서버에서 CSRF 구현

lottogame 2020. 11. 6. 07:49
반응형

Asp.Net WebApi에 대한 Angular, 서버에서 CSRF 구현


ASP.NET WebAPI 백엔드를 치는 Angular.js에서 웹 사이트를 구현하고 있습니다.

Angular.js에는 anti-csrf 보호에 도움이되는 몇 가지 내장 기능이 있습니다. 각 http 요청에서 "XSRF-TOKEN"이라는 쿠키를 찾아 "X-XSRF-TOKEN"이라는 헤더로 제출합니다.

이는 사용자를 인증 한 후 X-XSRF-TOKEN 헤더에서 수신 요청을 확인한 후 웹 서버가 XSRF-TOKEN 쿠키를 설정할 수 있어야합니다.

각도 문서 상태 :

이를 활용하려면 서버가 첫 번째 HTTP GET 요청에서 XSRF-TOKEN이라는 JavaScript 판독 가능 세션 쿠키에 토큰을 설정해야합니다. 후속 비 GET 요청에서 서버는 쿠키가 X-XSRF-TOKEN HTTP 헤더와 일치하는지 확인할 수 있으므로 도메인에서 실행중인 JavaScript 만 토큰을 읽을 수 있는지 확인할 수 있습니다. 토큰은 각 사용자에 대해 고유해야하며 JavaScript가 자체 토큰을 구성하지 않도록 서버에서 확인할 수 있어야합니다. 보안 강화를 위해이 토큰은 솔트가 포함 된 사이트 인증 쿠키의 다이제스트 인 것이 좋습니다.

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

그런 다음 권한 부여 컨트롤러에 다음 메서드가 있으며 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()
    {
        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");

누구든지 그 접근 방식에서 명백한 (또는 그렇게 분명하지 않은) 문제를 발견 할 수 있습니까?


귀하의 코드는 괜찮은 것 같습니다. 유일한 것은 web.api가 asp.net mvc의 "상위"에서 실행되므로 보유하고있는 대부분의 코드가 필요하지 않으며, 후자는 위조 방지 토큰을 지원합니다.

댓글에서 dbrunning 및 ccorrin은 MVC html 도우미를 사용할 때만 AntiForgery 토큰에서 빌드를 사용할 수 있다는 우려를 표현합니다. 사실이 아닙니다. 도우미는 서로에 대해 유효성을 검사 할 수있는 세션 기반 토큰 쌍을 노출 할 수 있습니다. 자세한 내용은 아래를 참조하십시오.

최신 정보:

There is two methods you can use from AntiForgery:

  • AntiForgery.GetTokens uses two out parameters to return cookie token and form token

  • AntiForgery.Validate(cookieToken, formToken) validates if pair of tokens is valid

You totally can repurpose those two methods and use formToken as headerToken and cookieToken as actual cookieToken. Then just call validate on both within attribute.

Another solution is to use JWT (check eg MembershipReboot implementation)

This link shows how to use built in anti-forgery tokens with 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);
}

Also take a look at this question AngularJS can't find XSRF-TOKEN cookie


I think your code is flawed. The whole idea around prevent CSRF is to prevent a unique token on each REQUEST, not each session. If the anti-forgery token is a session persisted value, the ability to perform CSRF still remains. You need to provide a unique token on each request...


This solution isn't secure since CSRF attacks are still possible as long as the Auth cookie is valid. Both the auth and the xsrf cookie will be sent to the server when an attacker makes you perform a request via another site, and therefore you are still vulnerable until the user does a "hard" logout.

Each request or session should have its own unique token to truly prevent CRSF attacks. But probably the best solution is to not use cookie based authentication but token based authentication such as OAuth. This prevents other websites from using your cookies to perform unwanted requests, since the tokens are used in http headers instead of cookies. And http headers are not automatically send.

  1. Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
  2. AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity

These excellent blog posts contain information of how to implement OAuth for WebAPI. The blog posts also contains great information of how to integrate it with AngularJS.

Another solution might be to disable CORS and only accept incoming requests from whitelisted domains. However this won't work for non-website applications, such as mobile and/or desktop clients. Next to that once your website is vulnerable to a XSS attack the attacker will still be able to forge requests on your behalve.


Haven't had any problems pointed out with the code, so I consider the question answered.

참고URL : https://stackoverflow.com/questions/15574486/angular-against-asp-net-webapi-implement-csrf-on-the-server

반응형