Przeglądarka nie ustawia pliku cookie ASP.NET_SessionId na żądanie postu bramki płatniczej na naszej stronie

12

Mamy dziwny problem z procesem płatności naszej aplikacji internetowej, który powoduje utratę danych sesji.

W tym procesie użytkownik po przekierowaniu na stronę dostawcy płatności jest przekierowywany na stronę dostawcy płatności i przekierowywany z powrotem na naszą stronę (na określony przez nas adres URL), gdy tylko on tam zrobi. To ostatnie przekierowanie odbywa się na podstawie oceny kodu HTML dostawcy usług płatniczych w przeglądarce, który zasadniczo składa się z formularza publikującego na naszej stronie i kilku wierszy kodu javascript, który publikuje ten formularz podczas ładowania strony. W tym momencie przeglądarka wysyła żądanie wysyłania, ale nie ustawia pliku cookie „ASP.NET_SessionId”, który jest obecny w poprzednich żądaniach złożonych w tej samej domenie (domenie naszej aplikacji). Co dziwniejsze, ustawia kolejny plik cookie o nazwie „AcceptCookie”. Po prostu wybiera upuszczenie pliku cookie „ASP.NET_SessionId”.

Aby zilustrować sytuację, zrobiłem kilka zrzutów ekranu. (Na tych zrzutach ekranu pomarańczowe i zielone prostokąty zawierają dokładnie tę samą wartość.)

  1. Jest to prośba (do naszej aplikacji), gdy użytkownik naciśnie przycisk „Sprawdź”. Po tym żądaniu użytkownik zostaje przekierowany na stronę dostawcy płatności.

żądanie wymeldowania

  1. Jest to ostatnia strona obsługiwana przez dostawcę płatności po tym, jak użytkownik tam skończy. Jak widać, jest to tylko prosty formularz, który jest automatycznie wysyłany do naszej domeny przy ładowaniu strony.

ostateczna odpowiedź dostawcy płatności

  1. Ale to żądanie postu nie zawiera pliku cookie „ASP.NET_SessionId”, co powoduje uzyskanie nowego identyfikatora sesji i utratę danych poprzedniej sesji. I znowu brakuje tylko „ASP.NET_SessionId”, a nie drugiej o nazwie „AcceptCookie”.

żądanie wysłania, które prowadzi użytkownika z powrotem do naszej witryny (wykonane za pomocą javascript w poprzednim kroku)

Wreszcie doszliśmy do wniosku, że w starszych wersjach przeglądarek problem ten nie występuje. W Firefoksie 52 działa to jak urok, ale w Firefoksie 71 występuje powyższy problem.

Jakieś pomysły?

Uwaga: jest to aplikacja ASP.NET MVC z targetFramework = "4.5.2"

Miłego dnia.

E. Özgür
źródło

Odpowiedzi:

16

Odkryliśmy to.

W jakiś sposób atrybut „SameSite” pliku cookie „ASP.NET_SessionId” domyślnie ma wartość „Lax”, co powoduje, że ciasteczko sesyjne nie jest dodawane do żądania wysłanego przez kod javascript bramy płatności.

Dodaliśmy następującą regułę do pliku web.config, aby zastąpić tę wartość i ustawić ją na „Brak”.

<configuration>
  <system.webServer>
    <rewrite>
      <outboundRules>
        <rule name="Add SameSite" preCondition="No SameSite">
          <match serverVariable="RESPONSE_Set_Cookie" pattern=".*" negate="false" />
          <action type="Rewrite" value="{R:0}; SameSite=None" />
          <conditions>
          </conditions>
        </rule>
        <preConditions>
          <preCondition name="No SameSite">
            <add input="{RESPONSE_Set_Cookie}" pattern="." />
            <add input="{RESPONSE_Set_Cookie}" pattern="; SameSite=None" negate="true" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

AKTUALIZACJA 1 : Dodanie powyższej konfiguracji rozwiązało problem współczesnych przeglądarek, ale zdaliśmy sobie sprawę, że nadal mamy problemy ze starszymi wersjami Micosoft Edge i Internet Explorer.

Musieliśmy więc dodać atrybut cookieSameSite = "None" do węzła sessionState w pliku web.config.

<sessionState cookieSameSite="None" />

Uważaj jednak na tę zmianę konfiguracji, ponieważ starsze wersje .NET Framework nie obsługują jej i powodują wyświetlanie strony błędu.

Nawiasem mówiąc, nadal mamy problemy z przeglądarkami w IOS 12. Ale myślę, że jest to związane z tym potwierdzonym błędem

AKTUALIZACJA 2 : patrz odpowiedź Zemiena na ewentualną poprawkę dotyczącą problemu z IOS

AKTUALIZACJA 3 : Łącząc nasze ustalenia z sugestiami zawartymi w odpowiedzi zemien, opracowaliśmy następujące zasady przepisywania. Używamy tej konfiguracji w produkcji. Ale uwaga: oznacza wszystkie pliki cookie atrybutem „SameSite: None” dla zgodnych przeglądarek i wyklucza atrybut SameSite, jeśli istnieje, dla niekompatybilnych przeglądarek. Może się to wydawać skomplikowane, ale starałem się wyjaśnić za pomocą linii komentarza.

Oto końcowa konfiguracja, której używamy w produkcji:

<configuration> 

  <system.webServer>

    <rewrite>

      <outboundRules>

        <preConditions>
          <!-- Browsers incompatible with SameSite=None -->
          <preCondition name="IncompatibleWithSameSiteNone" logicalGrouping="MatchAny">
            <add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" />
            <add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" />
            <add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" />
          </preCondition>

          <!-- Rest of the browsers are assumed to be compatible with SameSite=None -->
          <preCondition name="CompatibleWithSameSiteNone" logicalGrouping="MatchAll">
            <add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" negate="true" />
            <add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" negate="true" />
            <add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" negate="true" />
          </preCondition>

        </preConditions>

        <!-- Rule 1: Remove SameSite part from cookie for incompatible browsers if exists -->
        <rule name="Remove_SameSiteCookie_IfExists_ForLegacyBrowsers" preCondition="IncompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
          <action type="Rewrite" value="{R:1}" />
        </rule>

        <!-- Rule 2: Override SameSite's value to None if exists, for compatible browsers -->
        <rule name="Override_SameSiteCookie_IfExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=.*)" />
          <action type="Rewrite" value="{R:1}; SameSite=None" />
        </rule>

        <!-- Rule 3: Add SameSite attribute with the value None if it does not exists, for compatible browsers -->
        <rule name="Add_SameSiteCookie_IfNotExists_ForModernBrowsers" preCondition="CompatibleWithSameSiteNone">
          <match serverVariable="RESPONSE_Set-Cookie" pattern=".*"/>
          <!-- Condition explanation: Cookie data contains some string value but does not contain SameSite attribute -->
          <conditions logicalGrouping="MatchAll">
            <add input="{R:0}" pattern="^(?!\s*$).+"/>
            <add input="{R:0}" pattern="SameSite=.*" negate="true"/>
          </conditions>
          <action type="Rewrite" value="{R:0}; SameSite=None" />
        </rule>

      </outboundRules>

    </rewrite>    

  </system.webServer>  

</configuration>
E. Özgür
źródło
Dzięki @ EÖzgür. Ten problem pochodzi z KB4533097 ( support.microsoft.com/en-us/help/4533097/kb4533097 ) w szczególności KB4533011 (.net 4.7 i niższe) oraz KB4533004 (.net 4.8) wydane 10 grudnia
S. Pineau
Mam ten sam problem, ale czasami asp.net mvc daje klientowi ASP.NET_SessionId pliki cookie z LAX, czasem z BRAK. Nie jestem pewien, dlaczego tak się dzieje. Mam na myśli, że powinien to być LAX przez cały czas, ale mimo to, kiedy loguję się na stronie, mogę uzyskać BRAK.
Duke
O stary! Przez dwa dni zwariowałem na punkcie tego problemu. Wreszcie twoja odpowiedź uratowała mi dzień i frustrację. Dzięki.
Hemanth
1
Ten problem wystąpił na serwerze 2016 po zastosowaniu aktualizacji z grudnia. (KB4530689). Wielkie dzięki za znalezienie rozwiązania!
user0474975
Czy to dotyczy tylko rdzenia dotnet? W mojej aplikacji Framework pokazuję te opcje jako niepoprawne wartości do ustawienia.
IronSean
3

Zmodyfikowałem kilka odpowiedzi SO, aby wymyślić przepisywanie adresów URL, które dodaje SameSite=Nonesesyjne pliki cookie, a także usuwam SameSite=Noneze wszystkich plików cookie w większości niezgodnych przeglądarek. Celem tego przepisania jest zachowanie „starszego” zachowania sprzed Chrome 80.

Pełny opis na moim blogu Coder Frontline :

<rewrite>
  <outboundRules>
    <preConditions>
      <!-- Checks User Agent to identify browsers incompatible with SameSite=None -->
      <preCondition name="IncompatibleWithSameSiteNone" logicalGrouping="MatchAny">
        <add input="{HTTP_USER_AGENT}" pattern="(CPU iPhone OS 12)|(iPad; CPU OS 12)" />
        <add input="{HTTP_USER_AGENT}" pattern="(Chrome/5)|(Chrome/6)" />
        <add input="{HTTP_USER_AGENT}" pattern="( OS X 10_14).*(Version/).*((Safari)|(KHTML, like Gecko)$)" />
      </preCondition>
    </preConditions>

    <!-- Adds or changes SameSite to None for the session cookie -->
    <!-- Note that secure header is also required by Chrome and should not be added here -->
    <rule name="SessionCookieAddNoneHeader">
      <match serverVariable="RESPONSE_Set-Cookie" pattern="((.*)(ASP.NET_SessionId)(=.*))(SameSite=.*)?" />
      <action type="Rewrite" value="{R:1}; SameSite=None" />
    </rule>

    <!-- Removes SameSite=None header from all cookies, for most incompatible browsers -->
    <rule name="CookieRemoveSameSiteNone" preCondition="IncompatibleWithSameSiteNone">
      <match serverVariable="RESPONSE_Set-Cookie" pattern="(.*)(SameSite=None)" />
      <action type="Rewrite" value="{R:1}" />
    </rule>
  </outboundRules>
</rewrite>

Powinno to działać w przypadku większości aplikacji ASP .Net i ASP .Net Core, chociaż nowsze platformy mają odpowiedni kod i opcje konfiguracji umożliwiające kontrolowanie tego zachowania. Przed użyciem mojego przepisywania powyżej poleciłbym zbadanie wszystkich dostępnych opcji.

zemien
źródło