42 votes

Pourquoi le navigateur ne réutilise-t-il pas les en-têtes d'autorisation après un XMLHttpRequest authentifié?

Je suis le développement de Single Page App à l'aide Angulaire. Le backend expose RESTE des services qui nécessitent une authentification de Base. Arriver index.html ou l'un des scripts ne nécessite pas d'authentification.

J'ai une drôle de situation où l'un de mon point de vue a un <img> où l' src correspond à l'url d'une API REST qui nécessite une authentification. L' <img> est traité par le navigateur et je n'ai aucune chance de définir l'en-tête d'autorisation pour OBTENIR la demande de il fait. Qui provoque le navigateur demande d'informations d'identification.

J'ai tenté de résoudre ce problème en faisant ceci:

  1. Laissez img src vide dans la source
  2. Au document "prêt", faire un XMLHttpRequest à un service (/api/login) avec l'Autorisation d'en-tête, juste à cause de l'authentification à se produire.
  3. À l'issue de cet appel, régler le img src d'attribut, en pensant que d'ici là, le navigateur ne sais pour inclure l'en-tête d'Autorisation dans les requêtes suivantes...

...mais il ne le fait pas. La demande pour l'image sort sans les en-têtes. Si j'entrez les informations d'identification, puis toutes les autres images sur la page de droite. (J'ai aussi essayé et Angulaire de l' ng-src , mais qui a produit le même résultat)

J'ai deux questions:

  1. Pourquoi ne pas le navigateur (IE10) inclure les en-têtes à toutes les demandes après le succès de l' XMLHttpRequest?
  2. Que puis-je faire pour contourner ce problème?

@bergi demandé pour les demandes d'informations. Ils sont ici.

Demande d' /api/login

GET https://myserver/dev30281_WebServices/api/login HTTP/1.1
Accept: */*
Authorization: Basic <header here>
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729)
Connection: Keep-Alive

Réponse (/api/login)

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 4
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 20 Dec 2013 14:44:52 GMT

Demande d' /utilisateur/image/2218:

GET https://myserver/dev30281_WebServices/api/user/picture/2218 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729)
Connection: Keep-Alive

Et puis le navigateur web de demande d'informations d'identification. Si j'entre eux, je reçois cette réponse:

HTTP/1.1 200 OK
Cache-Control: public, max-age=60
Content-Length: 3119
Content-Type: image/png
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 20 Dec 2013 14:50:17 GMT

24voto

ComFreek Points 14185

L'idée de base

Charger les images via JavaScript et de les afficher sur le site. L'avantage est que les informations d'authentification ne sera jamais à trouver leur chemin dans le code HTML. Ils résistent à du JavaScript côté.

Étape 1: charger les données d'image via JS

C'est la base de la fonctionnalité AJAX (voir aussi XMLHttpRequest::open(method, uri, async, user, pw)):

var xhr = new XMLHttpRequest();
xhr.open("GET", "your-server-path-to-image", true, "username", "password");

xhr.onload = function(evt) {
  if (this.status == 200) {
    // ...
  }
};

Étape 2: format de données

Maintenant, comment pouvons-nous afficher les données d'image? Lors de l'utilisation de HTML, normalement attribuer une URI de l' src attribut de l'élément d'image. Nous pouvons appliquer le même principe ici, sauf pour le fait que nous utilisons des données Uri au lieu de "normal" http(s):// des produits dérivés.

xhr.onload = function(evt) {
  if (this.status == 200) {
    var b64 = utf8_to_b64(this.responseText);
    var dataUri = 'data:image/png;base64,' + b64; // Assuming a PNG image

    myImgElement.src = dataUri;
  }
};

// From MDN:
// https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
function utf8_to_b64( str ) {
    return window.btoa(unescape(encodeURIComponent( str )));
}

Toile

Il y a aussi une autre option, qui consiste à peindre les données chargées dans un <canvas> champ. De cette façon, l'utilisateur ne sera pas en mesure de cliquer droit sur l'image (la zone où la toile est positionné), par opposition à l' <img> et de données Uri où l'utilisateur verra une longue données URI lors de la visualisation de l'image du panneau propriétés.

9voto

flup Points 12250

Le google drive uploader est créé à l'aide d'angular js. Ses auteurs face à un problème similaire. Les icônes ont été hébergés sur un autre domaine et de les mettre en tant que img src= violé le CSP. Donc, comme vous, qu'ils étaient obligés d'aller chercher les images de l'icône à l'aide de XHR, puis en quelque sorte réussi à obtenir dans l' img tags.

Ils décrivent comment ils l'ont résolu. Après l'extraction de l'image à l'aide de XHR, ils l'écrivent à l'HTML5 système de fichiers local. Ils ont mis son URL sur le système de fichiers local dans l' imgs' src d'attribut à l'aide de l' ng-src directive.

$http.get(doc.icon, {responseType: 'blob'}).success(function(blob) {
  console.log('Fetched icon via XHR');
  blob.name = doc.iconFilename; // Add icon filename to blob.
  writeFile(blob); // Write is async, but that's ok.
  doc.icon = window.URL.createObjectURL(blob);
  ...
}

Comme pour le pourquoi, je ne sais pas. Je suppose que la création d'un jeton de session pour récupérer les images est hors de question? Je m'attends à ce Cookie en-têtes ne soient envoyés? C'est une croix-origine de la demande? Dans ce cas, pouvez-vous définir le withCredentials propriété? Est-il un P3P chose, peut-être?

4voto

SzabV Points 196

Une autre approche serait d'ajouter un point de fin pour vos sites de back-end qui mandaté la demande d'image. Pour que votre page pourrait demander sans informations d'identification et l'extrémité arrière serait de prendre soin de l'authentification. La fin pourrait aussi le cache de l'image si elle n'a pas changé fréquemment ou que vous saviez la fréquence avec laquelle il a été mis à jour. C'est assez facile à faire sur le back-end, rend votre frontal simple et permet d'éviter les informations d'identification d'être envoyé au navigateur.

Si le problème de l'authentification est alors le lien pourrait contenir un jeton généré pour l'utilisateur est authentifié et uniquement accessibles à partir de leur navigateur web en cours de session. Donnant accès sécurisé pour le contenu que pour l'utilisateur, il a été prévu pour et uniquement pour le temps qu'ils sont autorisés à y accéder. Cela exigerait aussi travailler dans le back-end, cependant.

2voto

Jonas Hartmann Points 952

Il me semble que pour résoudre votre problème, vous devez modifier la conception de votre application, au lieu d'essayer de pirater votre chemin autour de la manière dont les navigateurs fonctionnent réellement.

Une demande pour une URL sécurisée aura toujours besoin de l'authentification, au sujet de celui-ci étant effectué par le navigateur avec une balise img ou en javascript.

Si vous pouvez effectuer l'autorisation automatiquement sans interaction de l'utilisateur, vous pouvez le faire sur le côté serveur et vous n'avez pas besoin d'envoyer n'importe quel utilisateur+pass pour le client de le faire. Si c'est le cas, vous pouvez changer le code-behind https://myserver/dev30281_WebServices/api/user/picture/2218 afin de procéder à l'autorisation et à servir de l'image, sans HTTP auth, seulement si l'utilisateur est autorisé à demander, sinon, le retour d'un 403 forbidden réponse (http://en.wikipedia.org/wiki/HTTP_403).

Une autre solution possible serait de séparer les pages qui contiennent les images sécurisées du reste de l'application. Donc, vous, en théorie, deux single page apps. L'utilisateur sera invité à vous identifier pour accéder à la partie sécurisée. Je n'en suis pas sûr si cela est possible dans votre cas, puisque vous n'avez pas état de toutes les exigences. Mais il fait plus de sens que si vous voulez servir d'obtenir des ressources qui nécessitent une authentification, l'utilisateur doit être invité pour les informations d'identification, tout comme le navigateur n'.

2voto

Sergey Pekar Points 984

Je toujours analyser

Définissez la valeur de l'en - tête Cookie dans la précédente (ou la première demande de connexion), puis envoyez-la dans les demandes suivantes.

Quelque chose comme ça

Réponse après la première demande:

 Date:Thu, 26 Dec 2013 16:20:53 GMT
Expires:-1
Pragma:no-cache
Set-Cookie:ASP.NET_SessionId=lb1nbxeyfhl5suii2hfchxpx; domain=.example.com; path=/; secure; HttpOnly
Vary:Accept-Encoding
X-Cdn:Served-By-Akamai
X-Powered-By:ASP.NET
 

Toute demande suivante:

 Accept:text/html,application/xhtml+xml
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Cache-Control:no-cache
Connection:keep-alive
Cookie:ASP.NET_SessionId=lb1nbxeyfhl5suii2hfchxpx;
 

Comme vous pouvez le voir, j'envoie ASP.NET_SessionId = "toute valeur" dans l'en-tête de cookie . Si le serveur utilise php, vous devez analyser PHPSESSID = "une valeur"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X