Символы 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?
Ответы
Ответ 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
Надеюсь, это поможет. Просто пытаюсь немного вернуть сообщество!