web-dev-qa-db-fra.com

Pourquoi la demande de contrôle en amont OPTIONS d’une demande CORS authentifiée fonctionne-t-elle dans Chrome mais pas Firefox?)?

J'écris un client JavaScript à inclure sur des sites tiers (pensez au bouton J'aime de Facebook). Il doit extraire des informations d'une API nécessitant une authentification HTTP de base. La configuration simplifiée ressemble à ceci:

Un site tiers inclut cet extrait sur leur page:

<script 
async="true"
id="web-dev-widget"
data-public-key="pUbl1c_ap1k3y"
src="http://web.dev/widget.js">
</script>

widget.js appelle l'API:

var el = document.getElementById('web-dev-widget'),
    user = 'token',
    pass = el.getAttribute('data-public-key'),
    url = 'https://api.dev/',
    httpRequest = new XMLHttpRequest(),
    handler = function() {
      if (httpRequest.readyState === 4) {
        if (httpRequest.status === 200) {
          console.log(httpRequest.responseText);
        } else {
          console.log('There was a problem with the request.', httpRequest);
        }
      }
    };

httpRequest.open('GET', url, true, user, pass);
httpRequest.onreadystatechange = handler;
httpRequest.withCredentials = true;
httpRequest.send();

L'API a été configurée pour répondre avec les en-têtes appropriés:

Header set Access-Control-Allow-Credentials: true
Header set Access-Control-Allow-Methods: "GET, OPTIONS"
Header set Access-Control-Allow-Headers: "Origin, authorization, accept"
SetEnvIf Origin "http(s)?://(.+?\.[a-z]{3})$" AccessControlAllowOrigin=$0
Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin

Notez que le paramètre Access-Control-Allow-Origin Est défini sur Origin au lieu d'utiliser un caractère générique car j'envoie une demande avec informations d'identification (withCredentials).

Tout est maintenant en place pour faire une requête authentifiée asynchrone entre domaines, et cela fonctionne très bien dans Chrome 25 sur OS X 10.8.2. Dans Outils de développement, je peux voir la requête réseau de la OPTIONS demande avant la demande GET, et la réponse revient comme prévu.

Lors des tests dans Firefox 19, aucune demande réseau n'apparaît dans l'API Firebug et cette erreur est consignée dans la console: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied

Après de longues recherches, j'ai constaté que Gecko n'autorise pas le nom d'utilisateur et le mot de passe à se trouver directement dans un URI intersite en fonction des commentaires. J'ai supposé que c'était en utilisant les paramètres optionnels user et password pour open(), alors j'ai essayé l'autre méthode de création de requêtes authentifiées consistant à coder en base64 les informations d'identification et à envoyer un en-tête Authorization:

// Base64 from http://www.webtoolkit.info/javascript-base64.html
auth = "Basic " + Base64.encode(user + ":" + pass);

...
// after open() and before send()
httpRequest.setRequestHeader('Authorization', auth);

Cela se traduit par une réponse 401 Unauthorized À la demande OPTIONS qui aboutit à des recherches dans Google telles que "Pourquoi cela fonctionne-t-il dans Chrome et non Firefox !?" quand j'ai su que j'avais des problèmes.

Pourquoi fait cela fonctionne dans Chrome et pas Firefox? Comment puis-je obtenir la demande OPTIONS d’envoyer et de répondre de manière cohérente?

58
maxbeatty

Pourquoi fait ça marche dans Chrome et pas Firefox?

Le spécification W3 pour les demandes de contrôle en amont de CORS indique clairement que les informations d'identification de l'utilisateur doivent être exclues. Il y a un bogue dans Chrome et WebKitOPTIONS les requêtes retournant un statut de 401 envoient toujours la requête suivante.

Firefox a un fichier de bogues associé qui se termine par un lien vers la liste de diffusion W3 public webapps demandant que la spécification CORS soit modifiée afin de permettre l'envoi d'en-têtes d'authentification sur le OPTIONS requête au profit de IIS utilisateurs. En gros, ils attendent que ces serveurs soient obsolètes.

Comment puis-je obtenir la demande OPTIONS d’envoyer et de répondre de manière cohérente?

Demandez simplement au serveur (API dans cet exemple) de répondre aux requêtes OPTIONS sans requérir d'authentification.

Kinvey a fait du bon travail en développant ce lien tout en créant un lien vers n problème de l'API Twitter décrivant de manière intéressante le problème du problème de ce scénario, quelques semaines avant le début du mois précédent. les problèmes de navigateur ont été classés.

118
maxbeatty

Ceci est un ancien post mais cela pourrait peut-être aider les gens à résoudre le problème de la SCRO. Pour résoudre le problème d’autorisation de base, évitez d’autoriser les requêtes OPTIONS sur votre serveur. Ceci est un exemple de configuration Apache. Ajoutez simplement quelque chose comme ceci dans votre VirtualHost ou votre emplacement.

<LimitExcept OPTIONS>
    AuthType Basic
    AuthName <AUTH_NAME>
    Require valid-user
    AuthUserFile <FILE_PATH>
</LimitExcept>
2

C'était particulier pour moi. J'envoie un en-tête nommé 'SESSIONHASH'. Aucun problème pour Chrome et Opera, mais Firefox souhaite également que cet en-tête apparaisse dans la liste "Accès-Contrôle-Autoriser-en-têtes". Sinon, Firefox émettra l'erreur CORS.

0
bitkorn