Состязайтесь с 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");
Может ли кто-нибудь определить какие-либо очевидные (или не столь очевидные) проблемы с таким подходом?