web-dev-qa-db-fra.com

Cookies avec et sans le domaine spécifié (incohérence du navigateur)

J'ai remarqué qu'il existe de réelles incohérences entre les navigateurs en termes de cookies.

Cela va être assez long alors soyez indulgent avec moi.

Remarque: J'ai configuré un domaine dans mon fichier hôte appelé "testdomain.com", ce bug NE fonctionnera PAS lors de l'utilisation de "localhost".

Note2: Je suis curieux de savoir comment cela fonctionne sur Apache/PHP si lorsque vous récupérez un cookie par son nom s'il redonne une collection de cookies.

Wikipédia

Wikipedia indique que: http://en.wikipedia.org/wiki/HTTP_cookie#Domain_and_Path

Domaine et chemin
Le domaine et le chemin du cookie définissent la portée du cookie: ils indiquent au navigateur que les cookies ne doivent être renvoyés au serveur que pour le domaine et le chemin donnés. S'ils ne sont pas spécifiés, ils prennent par défaut le domaine et le chemin de l'objet demandé.

Donc, si nous poussons vers le bas:

Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

Nous devons obtenir un cookie avec le domaine utilisé étant le domaine de l'objet demandé, dans ce cas, il doit s'agir de "testdomain.com".

W3

W3 déclare dans la spécification pour les cookies: http://www.w3.org/Protocols/rfc2109/rfc2109

Domaine = domaine

Optionnel. L'attribut Domain spécifie le domaine pour lequel le cookie est valide. Un domaine explicitement spécifié doit toujours commencer par un point.

Donc, si nous poussons vers le bas:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});

Nous avons poussé le nom d'hôte de manière explicite, nous devrions obtenir un nom de domaine défini sur le cookie qui serait préfixé par le point, dans ce cas, il devrait être ".testdomain.com".

Il indique également ce qui est sur Wikipédia:

Le domaine par défaut est l'hôte de demande. (Notez qu'il n'y a pas de point au début de l'hôte de demande.)


Jusqu'à présent avec moi?

Si j'utilise la première méthode, définissant un domaine:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});

Voici les résultats:

IE9: 1 cookie

IE with 1 cookie and domain explicitly set

Opera: 1 cookie

Opera with 1 cookie and domain explicitly set

Firefox: 1 cookie

Firefox with 1 cookie and domain explicitly set

Chrome: 1 cookie

Chrome with 1 cookie and domain explicitly set

Comme vous pouvez le voir, les deux Opera et IE définissent tous deux un domaine EXPLICIT sans le préfixe de point).

Firefox et Chrome définissez le domaine EXPLICIT avec un préfixe de point.

Si j'utilise le code suivant:

Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

IE/Opera: les deux ont exactement le même résultat, le domaine SANS le préfixe de point.

Curieusement, Firefox et Chrome créent tous deux des cookies SANS le préfixe de point.

(J'ai effacé tous les cookies et exécuté à nouveau le code)

Firefox:

Firefox with 1 cookie and domain explicitly set

Chrome:

Chrome with 1 cookie and domain explicitly set

Mors intéressant

C'est là que ça devient intéressant. Si j'écris les cookies l'un après l'autre comme ceci:

Response.Cookies.Add(new HttpCookie("Banana", "1")
{
    Domain = Request.Url.Host
});
Response.Cookies.Add(new HttpCookie("Banana", "2")
{

});

PERSONNELLEMENT, je m'attendrais à ce qu'un cookie existe dans le navigateur, car je suppose qu'il est basé sur le nom du cookie.

Voici ce que j'ai observé:

Dans IE/Opera, le dernier ensemble de cookies est le cookie utilisé. En effet, le nom du cookie et le nom de domaine sont identiques.

Si vous définissez explicitement un nom de domaine avec un point, les deux navigateurs verront toujours 1 cookie, le dernier cookie du même nom.

Chrome et Firefox d'autre part, voir plus d'un cookie:

J'ai écrit le JavaScript suivant pour vider les valeurs sur la page:

<script type="text/javascript">

(function () {
    var cookies = document.cookie.split(';');
    var output = "";

    for (var i = 0; i < cookies.length; i++) {
        output += "<li>Name " + cookies[i].split('=')[0];
        output += " - Value " + cookies[i].split('=')[1] + "</li>";
    }

    document.write("<ul>" + output + "</ul>");
})();

</script>

Voici les résultats:

IE - 2 cookies (le navigateur en voit 1):

IE - 2 cookies set, the outcome

Opera - 2 cookies (le navigateur en voit 1):

enter image description here

Firefox - 2 cookies définis et le navigateur en voit 2 !:

enter image description here

Chrome - 2 cookies définis et le navigateur en voit 2 !:

enter image description here


Maintenant, vous vous demandez probablement ce que c'est.

Bien:

  1. Lorsque vous accédez au cookie par nom en C #, il vous donne 1 cookie. (le premier cookie qui porte ce nom)
  2. Le navigateur envoie TOUS les cookies au serveur
  3. Le navigateur n'envoie aucune information autre que la clé/valeur du cookie. (cela signifie que le serveur ne se soucie pas du domaine)
  4. Vous pouvez accéder aux deux cookies du même nom, si vous les récupérez par index

Le problème...

Nous avons dû changer notre authentification pour spécifier le domaine dans le cookie lorsque nous l'avons poussé vers le bas.

Cela a cassé Chrome et Firefox, les utilisateurs ne pouvaient plus se connecter, car le serveur tenterait d'authentifier l'ancien cookie d'authentification. En effet (d'après ma compréhension), il utilise le nom du cookie d'authentification pour récupérer le cookie.

Même s'il y a deux cookies, le premier est récupéré qui se trouve être l'ancien, l'authentification échoue, l'utilisateur n'est pas connecté. PARFOIS, le cookie correct est le premier dans la liste et l'authentification réussit ...

Initialement, nous avons résolu ce problème en poussant un cookie avec l'ancien domaine pour le faire expirer. Cela a fonctionné dans Chrome et Firefox.

Mais il a maintenant cassé IE/Opera car les deux navigateurs ne se soucient pas du domaine et comparent uniquement le cookie en fonction du nom.

Ma conclusion est que le domaine sur un cookie est une perte de temps totale.

En supposant que nous devons spécifier le domaine et que nous ne pouvons pas compter sur les utilisateurs pour vider le cache de leur navigateur. Comment pouvons-nous résoudre ce problème?

Mise à jour:

Analyser comment .NET déconnecte un utilisateur.

if (FormsAuthentication._CookieDomain != null)
{
    httpCookie.Domain = FormsAuthentication._CookieDomain;
}

Il semble qu'il soit tout à fait possible que l'authentification par formulaire envoie un cookie d'authentification expiré, qui n'a aucun lien avec le cookie avec lequel l'utilisateur est authentifié. Il n'utilise pas le domaine actuel du cookie d'authentification.

Ce qu'il ne peut pas utiliser de toute façon, car le domaine n'est pas renvoyé au serveur avec le cookie.

Update 2

Il semble que FormsAuthentication soit vraiment cassé. Si vous utilisez un nom de domaine explicite sur un cookie lorsque vous authentifiez l'utilisateur, attendez que la session expire, puis actualisez la page, la méthode de génération du cookie utilisé par FormsAuthentication entraîne la nullité du domaine, ce qui oblige le navigateur à attribuer un domaine sans point.

Cela nécessite que les formulaires soient affectés à un domaine à l'avance pour qu'il soit attribué au cookie, cela brise un système multi-locataire ...

44
Phill

La suggestion de @ WilliamBZA a aidé à résoudre le problème initial, mais le bogue de déconnexion/expiration de session qui entraîne la création d'un cookie de domaine implicite par le cookie m'a amené à la conclusion que la solution est ...

N'utilisez pas de cookies explicites dans .NET ... jamais

Il y a beaucoup trop de problèmes, assurez-vous qu'ils peuvent être résolus en étant explicites sur le formulaire/domaine, cookie/domaine, etc. Pour vous assurer que le domaine correct est utilisé partout. Mais si votre application héberge plusieurs domaines ou est multi locataire, cela devient trop problématique.

La leçon est apprise. N'utilisez pas de cookies explicites.

9
Phill

Je ne peux pas aider avec pourquoi les cookies sont traités différemment, mais une solution rapide serait d'utiliser un nom de cookie différent par sous-application plutôt que d'utiliser le domaine du cookie.

Dans le cas de l'authentification par formulaire, modifiez le nom du cookie ASPXAUTH.

5
WilliamBZA