2017-10-11 83 views
5

Mamy stronę z kilkoma formularzami. Każdy ma swój własny @Html.AntiForgeryToken(). Na mojej lokalnej maszynie wszystko jest świetne.__RequestVerificationToken nie zawsze jest tworzony

Wdrożono na platformę Azure (PAAS), ale __RequestVerificationTokennie jest tworzone na każde żądanie. Kiedyś jest tam i czasami dostaję Wymagany plik cookie zapobiegający fałszerstwu nie jest obecny i rzadko dostaję tokeny , które nie pasują do błędu.

W tej chwili jestem całkowicie nieświadomy. Nie mogę się dowiedzieć, czy coś jest nie tak w naszym kodzie lub w środowisku Azure? Brak ajax w tych formach.

Dodaliśmy sekcję <machineKey> do naszego web.config. Bez buforowania. Czasami pojawia się na nowych urządzeniach po raz pierwszy.

+0

Czy kiedykolwiek znalazłeś odpowiedź na to pytanie? –

+0

Nie, musieliśmy usunąć kontrolę antywłamaniową (była używana do prostych formularzy integracyjnych, nie ma w tym nic krytycznego). Nasza konfiguracja Azure miała dwie logiczne płyty CD, więc domyślam się, że jest związana z różnymi płytami CD obsługującymi żądanie i odpowiedź. To tylko moje przypuszczenie. – TamerM

+0

Przykro mi to słyszeć, chociaż nie sądzę, że powinno to stanowić problem, chyba że masz domenę zdefiniowaną również w działaniu formularza (co przekieruje użytkownika na inną płytę CD dla POST, ale wątpię, że będzie tak, ponieważ jeśli użyjesz UrlHelper, to nie przekieruje użytkowników między domenami). –

Odpowiedz

1

Wierzę, że Twój problem wynika z posiadania wielu formularzy z różnymi żetonami przeciwko fałszerstwu na jednej stronie. Gdy zażądasz strony, otrzymasz dwa różne tokeny w ukrytych polach formularzy, ale tylko jeden token w ciasteczkach. Formularz POST zawiera niedopasowane tokeny, które powodują błąd.

Wypróbuj sposób, w jaki AFT będzie działać, jeśli strona zawiera tylko jeden formularz. Jeśli działa poprawnie, moje założenie jest poprawne.

This answer zawiera możliwe rozwiązanie dla strony z wieloma formularzami, ale ma pewne wady bezpieczeństwa, jak wyjaśniono here.

Nie jestem pewien, dlaczego wszystko działa poprawnie na lokalnym hoście. Stworzyłem prostą aplikację i wypróbowałem formularz POST z poprawnym tokenem cookie, ale starym tokenem formularza z poprzedniej sesji. Ku mojemu zaskoczeniu taki POST z powodzeniem mija. Może być asp.net ma specjalne podejście do lokalnych żądań w tym przypadku. Nie znalazłem żadnych informacji na ten temat.

Jeśli moja odpowiedź nadal nie można pomóc prosimy o podanie następujących danych do dalszej analizy:

  1. oryginalne żądanie strony z nagłówków HTTP zwracanych i tworzą znaki przed fałszerstwem.
  2. Formularz żądania POST z wysłanymi nagłówkami HTTP.
+0

W oparciu o post OP, problem nie jest niedopasowaniem tokenów (btw, jeśli masz wiele tokenów), a także nie wydaje się problemem, który jest zawsze obecny. Ponadto program ASP.NET odszyfrowuje tokeny zapobiegające fałszowaniu przed porównaniem. Nie ma znaczenia, czy masz 2 różne tokeny w formularzu, jeśli oba zawierają dane odpowiadające plikowi cookie. Dodatkowo widzę we własnym systemie, że wiele formularzy i żetonów formularzy nie jest problemem, problemem jest to, że w ogóle nie ma żadnego pliku cookie wysłanego przez przeglądarkę. –

+0

Prawda, żetony nie są po prostu porównywane jako bufory binarne, ale są odszyfrowywane i porównywane z zachowanym znacznikiem bezpieczeństwa. Dobry artykuł na temat wewnętrznych tokenów przeciwdziałających fałszerstwom: https://www.codeproject.com/Articles/793384/ASP-NET-Anti-Forgery-Tokens-internals. OP wspomniał, że czasami dostaje "żetony nie pasują do błędu", więc moje założenie nadal może być problemem. Jeśli nie, to informacje, o które prosiłem u dołu mojej odpowiedzi, powinny wyjaśnić przynajmniej, czy jest to problem lokalnego klienta, czy zdalnego serwera. – CodeFuller

0

Po spędzeniu dużo czasu z dochodzenia, stosując kombinację Sentry i Azure logów serwera WWW, Znalazłem 2 głównych przyczyn wymienionych błędów:

1) na telefony komórkowe, kiedy przeglądarka znajduje się w tle, może zostać nagle zatrzymana przez system operacyjny w celu zwolnienia zasobów. W takim przypadku zwykle strona jest zapisywana na dysku telefonu i ponownie ładowana po ponownym otwarciu przeglądarki.

Problem polega na tym, że do tego czasu token anty-forgery, który jest plikiem cookie sesji, już wygasł, ponieważ jest to zasadniczo nowa sesja. Tak więc strona ładuje się bez użycia modułu Anti-Forgery Cookie, używając HTML z poprzedniej sesji. Powoduje to wyjątek The required anti-forgery cookie is not present.

2) Chociaż pozornie związany, wyjątek tokens do not match jest zwykle tylko stycznie spokrewniony. Przyczyną wydaje się zachowanie użytkownika podczas otwierania wielu kart w tym samym czasie.

Plik cookie zapobiegający fałszowaniu jest przypisywany tylko wtedy, gdy użytkownik dotrze do strony z formularzem. Oznacza to, że mogą przejść do Twojej strony głównej i nie mają pliku cookie zapobiegającego fałszerstwu. Następnie mogą otwierać wiele kart za pomocą kliknięcia środkowym przyciskiem myszy. Wielokrotne zakładki to wiele równoległych żądań, z których każda zawiera plik cookie zapobiegający fałszowaniu.

Ponieważ żądania te nie zawierają pliku cookie zapobiegającego fałszowaniu, dla każdego z nich program ASP.NET generuje osobny pseudolosowy plik cookie i używa go w formularzu; jednak zostanie zatrzymany tylko wynik ostatniego odebranego nagłówka. Oznacza to, że wszystkie pozostałe strony będą miały nieprawidłowe tokeny na stronie, ponieważ ich plik cookie zapobiegający fałszowaniu został nadpisany.

rozwiązania, jakie stworzył globalną że filtr powinien upewnić się, że

  1. Anti-Fałszerstwo cookie jest przypisany na dowolnej stronie, nawet jeśli strona nie ma formy i
  2. anty -Forgery cookie nie jest związane z sesją. Czas życia powinien być dopasowany do tokena logowania użytkownika, ale powinien się utrzymywać między sesjami, na wypadek gdyby urządzenie mobilne wczytało stronę bez sesji.

Poniższy kod to FilterAttribute, który należy dodać wewnątrz FilterConfig.cs jako filtr globalny. Proszę zauważyć, że chociaż nie wierzę, że spowodowałoby to lukę w zabezpieczeniach, nie jestem ekspertem od zabezpieczeń, więc wszelkie dane wejściowe są mile widziane.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 
public class AntiForgeryFilter : FilterAttribute, IActionFilter 
{ 
    public void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var cookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName); 
     var addCookie = true; 
     if (string.IsNullOrEmpty(cookie?.Value)) 
     { 
      cookie = filterContext.HttpContext.Response.Cookies.Get(AntiForgeryConfig.CookieName); 
      addCookie = false; 
     } 
     if (string.IsNullOrEmpty(cookie?.Value)) 
     { 
      AntiForgery.GetTokens(null, out string cookieToken, out string _); 
      cookie = new HttpCookie(AntiForgeryConfig.CookieName, cookieToken) 
      { 
       HttpOnly = true, 
       Secure = AntiForgeryConfig.RequireSsl 
      }; 
     } 
     cookie.Expires = DateTime.UtcNow.AddYears(1); 
     if(addCookie) filterContext.HttpContext.Response.Cookies.Add(cookie); 
    } 

    public void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
    } 
}