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

Символы UTF-8, искаженные в HTTP-имени пользователя Basic Auth

Я пытаюсь создать веб-сервис, используя Ruby on Rails. Пользователи аутентифицируются через HTTP Basic Auth. Я хочу разрешить любые допустимые символы UTF-8 в именах пользователей и паролях.

Проблема заключается в том, что браузер изменяет символы в учетных данных Basic Auth перед отправкой их на мою службу. Для тестирования я использую 'カ タ カ ナ カ タ カ カ カ タ カ カ ナ タ タ ナ カ カ タ カ ナ カ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ ナ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Если я воспринимаю это как строку и сделать username.unpack( "ч *" ), чтобы преобразовать его в шестнадцатеричном, я получаю: "3e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a8" Это кажется о праве на 32 кандзи символов (3 байта /6 шестнадцатеричных цифр в).

Если я сделаю то же самое с именем пользователя, которое входит через HTTP Basic auth, я получаю: 'Bafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaac. Это явно намного короче. Используя плагин Firefox Live HTTP Headers, здесь отображается фактический заголовок:

Authorization: Basic q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o6q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o=

Это выглядит так: строка "bafbba...", с высоким и низким размером nibbles (по крайней мере, когда я вставляю ее в Emacs, base 64 decode, а затем переключаюсь в режим hexl). Это может быть представление UTF16 имени пользователя, но я не получил ничего, чтобы отобразить его как нечто, кроме тарабарщины.

Rails настраивает заголовок типа контента на UTF-8, поэтому браузер должен отправлять эту кодировку. Я получаю правильные данные для отправки форм.

Проблема происходит как в Firefox 3.0.8, так и в IE 7.

Итак... есть ли какой-то волшебный соус для получения веб-браузеров для отправки символов UTF-8 через HTTP Basic Auth? Я что-то неправильно делаю на принимающей стороне? HTTP Basic Auth просто не работает с символами, отличными от ASCII?

4b9b3361

Ответ 1

Я хочу разрешить любые допустимые символы UTF-8 в именах пользователей и паролях.

Отказаться от надежды. Базовая аутентификация и Юникод не смешиваются.

Нет стандартного (*) для того, как кодировать символы, отличные от ASCII, в токены имени базовой аутентификации: пароль перед его базой. Следовательно, каждый браузер делает что-то другое:

  • Opera использует UTF-8;
  • IE использует стандартную кодовую страницу по умолчанию (которую вы не знаете, кроме нее никогда не UTF-8), и тихо управляет символами, которые не вписываются в нее, используя "угадывать" случайный символ, который выглядит бит, как тот, который вам нужен, или, может быть, просто не секретный рецепт;
  • Mozilla использует только младший байт символьных кодовых точек, который имеет эффект кодирования по ISO-8859-1 и безвозвратно уничтожает символы не-8859-1... кроме случаев, когда выполняется XMLHttpRequests, и в этом случае он использует UTF- 8;
  • Safari и Chrome кодируют ISO-8859-1 и не могут отправлять заголовок авторизации вообще, когда используется символ не 8859-1.

*: некоторые люди интерпретируют стандарт, чтобы сказать, что либо:

  • он должен быть всегда ISO-8859-1, из-за того, что он является кодировкой по умолчанию для включения сырых 8-битных символов, непосредственно включенных в заголовки;
  • он должен быть закодирован с использованием правил RFC2047. Как-то.

Но ни одно из этих предложений не относится к теме для включения в токен auth с кодировкой base64, а ссылка RFC2047 в спецификации HTTP действительно не работает вообще, поскольку все места, в которых она потенциально может быть использована, явно запрещены "Атомные контекстные правила самого RFC2047, даже если HTTP-заголовки соблюдают правила и расширения семейства RFC822, которых у них нет.

Вкратце: тьфу. Существует мало надежды на то, что это когда-либо фиксируется в стандарте или в браузерах, отличных от Opera. Это еще один фактор, который заставляет людей отказаться от базовой аутентификации HTTP в пользу нестандартных и менее доступных схем аутентификации на основе файлов cookie. Позор действительно.

Ответ 2

Известно, что обычная проверка подлинности не обеспечивает поддержку символов, отличных от ISO-8859-1.

Некоторые UA, как известно, используют UTF-8 вместо этого (Opera приходит на ум), но для этого не существует интероперабельности.

Насколько я могу судить, нет никакого способа исправить это, кроме как путем определения новой схемы аутентификации, которая обрабатывает все Unicode. И его развертывание.

Ответ 3

HTTP-дайджест-аутентификация также не является решением этой проблемы. Он испытывает такую ​​же проблему, когда клиент не может сообщить серверу, какой набор символов он использует, и сервер не может правильно предположить, что использовал клиент.

Ответ 4

Тестировали ли вы что-то вроде curl, чтобы убедиться, что это не проблема Firefox? HTTP Auth RFC отключен в ASCII и не-ASCII, но он говорит, что значение, переданное в заголовке, - это имя пользователя и пароль разделенные двоеточием, и я не могу найти двоеточие в строке, о которой сообщает Firefox.

Ответ 5

Если вы кодируете для Windows 8.1, обратите внимание, что образец в документации для HttpCredentialsHeaderValue (ошибочно) использует кодировку UTF-16. Достаточно хорошее исправление заключается в переключении на UTF-8 (поскольку ISO-8859-1 не поддерживается CryptographicBuffer.ConvertStringToBinary).

См. http://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.headers.httpcredentialsheadervalue.aspx.

Ответ 6

Я мог бы быть совершенно невежественным, но я пришел к этому сообщению, ища проблему при отправке строки UTF8 в виде заголовка внутри вызова ajax.

Я могу решить свою проблему, закодировав в Base64 строку непосредственно перед ее отправкой. Это означает, что вы можете с помощью простого JS преобразовать форму в base64 прямо перед отправкой, и таким образом ее можно переустановить на стороне сервера.

Эти простые инструменты позволили мне перенести строки utf8 как простые ASCII. Я обнаружил, что благодаря этому простому предложению:

base64 (эта кодировка предназначена для того, чтобы бинарные данные выдерживали транспорт через транспортные уровни, которые не являются 8-битными). http://www.webtoolkit.info/javascript-base64.html

Надеюсь, это поможет. Просто пытаюсь немного вернуть сообщество!