Подтвердить что ты не робот

Почему запрос Preflight OPTIONS аутентифицированного запроса CORS работает в Chrome, но не в Firefox?

Я пишу JavaScript-клиент, который будет включен на сторонние сайты (подумайте о кнопке Facebook Like). Он должен извлекать информацию из API, для которой требуется базовая HTTP-аутентификация. Упрощенная установка выглядит следующим образом:

Сайт сторонних разработчиков включает этот фрагмент на своей странице:

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

widget.js вызывает 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();

API был настроен на ответ с соответствующими заголовками:

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

Обратите внимание, что параметр Access-Control-Allow-Origin установлен в Origin вместо того, чтобы использовать подстановочный знак, потому что я отправляю запрос с подтверждением (withCredentials).

Теперь все работает, чтобы выполнить асинхронный междоменный аутентифицированный запрос, и он отлично работает в Chrome 25 на OS X 10.8.2. В Dev Tools я вижу запрос сети для запроса OPTIONS перед запросом GET, и ответ возвращается, как ожидалось.

При тестировании в Firefox 19 в Firebug API не появляются сетевые запросы, и эта ошибка регистрируется в консоли: NS_ERROR_DOM_BAD_URI: Access to restricted URI denied

После многократного поиска я обнаружил, что Gecko не позволяет пользователю и паролю быть непосредственно в межсайтовом URI в соответствии с комментариями. Я предположил, что это связано с использованием необязательных параметров пользователя и пароля для open(), поэтому я попробовал другой способ сделать аутентифицированные запросы, которые для Base64 кодируют учетные данные и отправляют в заголовок авторизации:

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

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

Это приводит к ответе 401 Unauthorized на запрос OPTIONS, который приводит к поисковым запросам Google, например: "Почему это работает в Chrome, а не в Firefox!?" Это, когда я знал, что у меня проблемы.

Почему он работает в Chrome, а не в Firefox? Как я могу получить запрос OPTIONS для отправки и ответа последовательно?

4b9b3361

Ответ 1

Почему это работает в Chrome, а не в Firefox?

Спецификация W3 для запросов предпросмотра CORS четко указывает, что учетные данные пользователя должны быть исключены. В Chrome есть ошибка: WebKit, где OPTIONS запросы, возвращающие статус 401, все еще отправляются последующий запрос.

Firefox содержит связанную с этим ошибку, которая заканчивается ссылкой на публичный список рассылки W3 publicappapp для замены спецификации CORS, чтобы разрешить отправку заголовков аутентификации по запросу OPTIONS в интересах пользователей IIS. В основном, они ожидают, что эти серверы будут устаревшими.

Как я могу получить запрос OPTIONS для отправки и ответа последовательно?

Просто попросите сервер (API в этом примере) ответить на OPTIONS запросы без проверки подлинности.

Kinvey проделала хорошую работу по этому вопросу, а также связала с проблему API Twitter кратко изложив проблему catch-22 этого точного сценария за пару недель до того, как были отправлены какие-либо проблемы с браузером.

Ответ 2

Это старый пост, но, возможно, это поможет людям решить проблему с CORS. Для завершения основной проблемы авторизации вам следует избегать авторизации запросов OPTIONS на вашем сервере. Это пример конфигурации Apache. Просто добавьте что-то подобное в ваш VirtualHost или Location.

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

Ответ 3

Это было особенно для меня. Я отправляю заголовок с именем 'SESSIONHASH'. Нет проблем для Chrome и Opera, но Firefox также хочет, чтобы этот заголовок был в списке "Access-Control-Allow-Headers". В противном случае Firefox выдаст ошибку CORS.