web-dev-qa-db-fra.com

Le navigateur ne définira pas le cookie ASP.NET_SessionId sur la demande de publication de la passerelle de paiement sur notre site

Nous rencontrons un problème étrange avec le processus de paiement de notre application Web qui entraîne la perte de données de session.

Dans ce processus, une fois que notre page de paiement est redirigée vers la page du fournisseur de paiement et redirigée vers notre site (vers une URL que nous spécifions) dès qu'il y a terminé. Cette dernière redirection est effectuée par l'évaluation par le navigateur du code html du fournisseur de paiement qui consiste essentiellement en un formulaire qui publie sur notre site et en quelques lignes de code javascript qui publie ce formulaire au chargement de la page. À ce stade, le navigateur effectue la demande de publication, mais ne définit pas le cookie "ASP.NET_SessionId" qui est présent dans les demandes précédentes effectuées sur le même domaine exact (le domaine de notre application). Ce qui est plus étrange, c'est qu'il définit un autre cookie que nous utilisons, nommé "AcceptCookie". Il choisit simplement de supprimer le cookie "ASP.NET_SessionId".

Pour illustrer la situation, j'ai pris quelques captures d'écran. (Dans ces captures d'écran, les rectangles orange et verts contiennent exactement la même valeur.)

  1. Il s'agit de la demande qui a été faite (à notre application) lorsque l'utilisateur appuie sur le bouton "Commander". Après cette demande, l'utilisateur est redirigé vers la page du fournisseur de paiement.

demande de règlement

  1. Il s'agit de la dernière page qui est servie par le fournisseur de paiement une fois que l'utilisateur y a terminé. Comme vous pouvez le voir, ce n'est qu'un simple formulaire qui est automatiquement publié sur notre domaine lors du chargement de la page.

réponse finale du prestataire de paiement

  1. Mais cette demande de publication n'inclut pas le cookie "ASP.NET_SessionId" qui entraîne l'acquisition d'un nouvel identifiant de session et la perte des données de session précédentes. Et encore une fois, juste "ASP.NET_SessionId" est manquant, pas l'autre nommé "AcceptCookie".

poster une demande qui ramène l'utilisateur sur notre site (faite avec javascript à l'étape précédente)

Enfin, nous avons pensé que sur les anciennes versions des navigateurs, ce problème ne se produit pas. Sur Firefox 52, cela fonctionne comme un charme, mais sur Firefox 71, le problème ci-dessus se produit.

Des idées?

Remarque: Il s'agit d'une application ASP.NET MVC avec targetFramework = "4.5.2"

Bonne journée.

12
E. Özgür

Nous l'avons compris.

D'une manière ou d'une autre, l'attribut "SameSite" du cookie "ASP.NET_SessionId" est défini par défaut sur "Lax", ce qui empêche l'ajout du cookie de session à la demande émise par le code javascript de la passerelle de paiement.

Nous avons ajouté la règle suivante au fichier web.config afin de remplacer cette valeur et de la définir sur "Aucune".

<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>

MISE À JOUR 1 : L'ajout de la configuration ci-dessus a résolu le problème pour les navigateurs modernes, mais nous avons réalisé que nous avions toujours des problèmes avec les anciennes versions de Micosoft Edge et Internet Explorer.

Nous avons donc dû ajouter l'attribut cookieSameSite = "None" au nœud sessionState dans le fichier web.config.

<sessionState cookieSameSite="None" />

Soyez prudent avec ce changement de configuration, car les anciennes versions du framework .net ne le prennent pas en charge et provoquent l'affichage de la page d'erreur de votre site.

Soit dit en passant, nous avons toujours des problèmes avec les navigateurs dans IOS 12. Mais je pense que c'est lié à ce bogue confirmé

MISE À JOUR 2 : voir la réponse de zemien pour un correctif possible sur IOS issue

MISE À JOUR 3 : En combinant nos résultats avec les suggestions de la réponse de zemien, nous avons trouvé les règles de réécriture suivantes. Nous utilisons cette configuration en production. Mais attention: il marque tous les cookies avec l'attribut "SameSite: None" pour les navigateurs compatibles et exclut l'attribut SameSite, s'il existe, pour les navigateurs incompatibles. Il peut semble compliqué mais j'ai essayé d'expliquer via les lignes de commentaires.

Voici la configuration FINALE que nous utilisons en production:

<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>
14
E. Özgür

J'ai modifié plusieurs SO réponses pour arriver à cette réécriture d'URL qui ajoute SameSite=None aux cookies de session, et également supprimer SameSite=None de tous les cookies pour la plupart des navigateurs incompatibles. Le but de cette réécriture est de conserver le comportement "hérité" pré-Chrome 80.

Rédaction complète dans mon Blog 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>

Cela devrait fonctionner pour la plupart des applications ASP .Net et ASP .Net Core), bien que les cadres plus récents disposent d'un code et d'options de configuration appropriés pour vous permettre de contrôler ce comportement. I recommanderais de rechercher toutes les options disponibles avant d'utiliser ma réécriture ci-dessus.

1
zemien