Состязайтесь с Asp.Net WebApi, внедрите CSRF на сервере

Я внедряю веб-сайт в Angular.js, который использует серверную часть ASP.NET WebAPI.

Angular.js имеет некоторые встроенные функции для защиты от csrf. При каждом запросе http он будет искать файл cookie с именем "XSRF-ЗНАК» и представить его в виде заголовка под названием "X-XSRF-TOKEN ".

Это основано на том, что веб-сервер может устанавливать cookie XSRF-TOKEN после аутентификации пользователя, а затем проверять заголовок X-XSRF-TOKEN на наличие входящих запросов.

Угловая документация состояния:

Чтобы воспользоваться этим, вашему серверу необходимо установить токен в файле cookie для чтения в JavaScript, который называется XSRF-TOKEN, при первом запросе HTTP GET. При последующих не GET-запросах сервер может проверить, соответствует ли cookie HTTP-заголовку X-XSRF-TOKEN, и, следовательно, быть уверенным, что только JavaScript, работающий в вашем домене, мог прочитать токен. Токен должен быть уникальным для каждого пользователя и должен проверяться сервером (чтобы JavaScript не создавал свои собственные токены). Мы рекомендуем, чтобы токен был дайджестом вашего сайта.Cookie для аутентификации с солью для дополнительной безопасности.

Я не могя не могу найти хорошие примеры этого для ASP.NET WebAPI, поэтому яЯ катался с помощью разных источников. Мой вопрос - кто-нибудь может увидеть что-то не так с кодом?

Сначала я определил простой вспомогательный класс:

public class CsrfTokenHelper
{
    const string ConstantSalt = "";

    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");

Может ли кто-нибудь определить какие-либо очевидные (или не столь очевидные) проблемы с таким подходом?

Ответы на вопрос(4)

Ваш ответ на вопрос