2016-06-22 3 views
2

Я работаю над приложением angular 2 с использованием бэкэнда ASP.Net MVC. Для этого index.cshtml включил @Html.AntiForgeryToken();, поэтому я возвращаю скрытый элемент ввода с токеном в качестве его значения. В моем интерфейсе я могу захватить этот токен и использовать его для моих запросов. Все идет нормально.Альтернативный способ для использования токена CSRF вместо использования @ Html.AntiForgeryToken() в ASP.Net MVC

Теперь, когда информация пользователя используется для генерации токена в бэкэнд, я должен отключить токен в некоторых случаях. Описана проблема here in this question.

Теперь, поскольку я не хочу делать полную перезагрузку страницы в своем приложении, я должен использовать обходной путь. Для этого я создал частичный вид в интерфейсе, который просто протягивает этот вход, используя @Html.AntiForgeryToken(); в ActionResult с простым методом, как это:

public ActionResult GetAntiForgery() 
{ 
    return PartialView("~/Views/Home/AntiForgery.cshtml"); 
} 

После Логин/выход из системы я вызвать эту функцию из моего интерфейса и заменить значение мои существующих AntiForgery input element вроде этого:

getAntiForgery(url:string) { 
     return this._http.get(url) 
      .map((response:any) => { 
       let originalXsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]'); 
       let body = response._body; 

       if(body) { 
        let helperElem = document.createElement('div'); 
        helperElem.innerHTML = body; 
        let helperInputElem = <HTMLInputElement>helperElem.firstChild; 
        originalXsrfElement.value = helperInputElem.value; 
       } 

       return response; 
      }); 
    } 

Я даже не могу сказать вам, что ошибки меня больше всего. Мне не нравится делать дополнительный запрос (но не позволяет погрузиться в это здесь), но для меня более страшным является то, что я должен что-то запросить, вернуть строку html и извлечь из нее строку токенов.

Если бы я был бэкэндом, я бы убил парня-фронтмена (меня ..) за то, что он даже думал о создании дополнительного частичного представления, создавая дополнительный метод и всегда делая два запроса на вход/выход из системы вместо одного.

Есть ли лучший способ? Например, я хотел бы назвать метод, который просто выдает JSON с правильным токеном вместо HTML snippet. Еще лучше, по существующим методам JsonResult в бэкэнд, я хотел бы добавить новый CSRF Token как собственность.

Я не архитектор, так что может быть что-то неправильно в общем, как я это делаю, но мои коллеги-бэкэнд не возражают против того, что я там делаю, поэтому это не должно быть так далеко.

Любые советы приветствуются.

+0

Похоже, этот вопрос может помочь (в основном ставит против подлога в заголовке АЯКС вместо скрытого поля): HTTP: // StackOverflow.com/questions/15416264/validateantiforgerytoken-with-spa-architecture – JohnnyFun

+0

Извините, не могу понять, как это помогает с моей проблемой. Вопрос другой. – lexith

+0

Раздел «Анти-CSRF и AJAX» в связанной статье кажется, что это может быть то, что вы ищете: http://www.asp.net/web-api/overview/security/preventing-cross-site- запрос-подлог-csrf-attack – JohnnyFun

ответ

1

Вы можете использовать AntiForgery.GetToken в своем действии, чтобы установить некоторое свойство на JSON возвращается:

string cookieToken, formToken; 
AntiForgery.GetTokens(null, out cookieToken, out formToken); 
json.RequestVerificationToken = cookieToken + ":" + formToken; 

Затем передать его обратно в заголовок вашего следующего запроса AJAX:

$.ajax("/my/awesome/url", { 
    type: "post", 
    contentType: "application/json", 
    data: { ... }, 
    dataType: "json", 
    headers: { 
     'RequestVerificationToken': requestVerificationToken 
    } 
}); 

С , он больше не обрабатывается с помощью файлов cookie, вы не можете просто использовать стандартный атрибут ValidateAntiForgeryToken. Вам нужно будет вручную проверить заголовок и проверить его. Тем не менее, вы должны быть в состоянии создать пользовательский атрибут можно использовать вместо:

AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 
public sealed class ValidateAntiForgeryTokenFromHeaderAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     var request = filterContext.HttpContext.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); 
    } 
} 

Тогда просто украсить свои действия с [ValidateAntiForgeryTokenFromHeader] вместо этого.

[Код адаптировано из http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks]

+0

То, что я не получаю, это вызов '@ Html.AntiForgeryToken()' вставляет фрагмент html, ввод с токеном в качестве значения. Это уже настроил файл cookie или почему ваше предложение не работает с файлами cookie? То, что я хочу, это просто получить значение '@ Html.AntiForgeryToken()' и отправить это строковое значение как ответ json вместо того, чтобы выдать представление. Ваш подход кажется немного излишним для меня только для этого небольшого «изменения». Как «Frontend: Server, дайте мне эту токенную строку». «Сервер: не жаль, что я могу только дать вам элемент html ...». Чего ждать? ;) – lexith

+0

Как правило, все, что вы попали по запросу AJAX, не поддерживало бы файлы cookie. Хорошо спроектированный API будет основан на REST, а REST - без гражданства (без сеанса, без файлов cookie). Web Api, безусловно, не поддерживает его. –