Какую кодировку следует использовать для базовой аутентификации HTTP?

87

RFC2617 говорит, что нужно кодировать имя пользователя и пароль в base64, но не говорит, какую кодировку символов использовать при создании октетов для ввода в алгоритм base64.

Должен ли я использовать US-ASCII или UTF8? Или кто-то уже где-то уладил этот вопрос?

Добс Вандермейер
источник

Ответы:

74

Исходная спецификация - RFC 2617

RFC 2617 можно читать как «ISO-8859-1» или «undefined». Твой выбор. Известно, что многие серверы используют ISO-8859-1 (нравится вам это или нет) и не работают, когда вы отправляете что-то еще. Так что, вероятно, единственный безопасный выбор - придерживаться ASCII.

Для получения дополнительной информации и предложения по исправлению ситуации см. Черновик «Параметр кодирования для базовой аутентификации HTTP» (который лег в основу RFC 7617).

Новый - RFC 7617

С 2015 года существует RFC 7617 , который отменяет RFC 2617. В отличие от старого RFC, новый RFC явно определяет кодировку символов, которая будет использоваться для имени пользователя и пароля.

  • Кодировка по умолчанию все еще не определена. Требуется только, чтобы он был совместим с US-ASCII (что означает, что он отображает байты ASCII в байты ASCII, как это делает UTF-8).
  • Сервер может дополнительно отправить дополнительный параметр аутентификации charset="UTF-8"в своем запросе, например:
    WWW-Authenticate: Basic realm="myChosenRealm", charset="UTF-8"
    Это объявляет, что сервер будет принимать символы, отличные от ASCII, в имени пользователя / пароле и ожидает, что они будут закодированы в UTF-8 (в частности, форма нормализации C) . Обратите внимание, что разрешен только UTF-8.

Полная версия:

Прочтите спецификацию . Если содержит дополнительные сведения, такие как точная процедура кодирования и список кодовых точек Unicode, которые должны поддерживаться.

Поддержка браузера

По состоянию на 2018 год современные браузеры обычно по умолчанию используют UTF-8, если пользователь вводит символы, отличные от ASCII, для имени пользователя или пароля (даже если сервер не использует charsetпараметр).

  • Chrome также, похоже, использует UTF-8
  • Internet Explorer не использует UTF-8 ( issue # 11879588 ).
  • Firefox экспериментирует с изменением, запланированным в настоящее время для версии 59 ( ошибка 1419658 ).

Царство

Параметр области по- прежнему поддерживает только символы ASCII даже в RFC 7617.

Джулиан Решке
источник
Спасибо, Джулиан. Я столкнулся с этим предложением, но, похоже, срок его действия истек, и я никуда не пошел. Жаль :-(.
Добс Вандермейер 01
1
Ваш ответ должен быть лучшим. Я могу перефразировать это точно как ASCII, может быть, ISO-8859-1, если вам повезет.
Добс Вандермейер 02
Похоже, что последняя версия 04 предложения (которая по совпадению, кажется, была опубликована сегодня) истекает 1 августа 2012 года.
Мишель ван Остерхаут,
Ответ был устаревшим, поскольку в нем не упоминался RFC 7617. Я отредактировал, чтобы включить это. Джулиан: Надеюсь, ты не против.
sleske
К сожалению, я только что понял, что вы на самом деле являетесь автором RFC 7617. Теперь я очень надеюсь, что я что-то исправил неправильно.
sleske
41

Краткий ответ: iso-8859-1, если не используются закодированные слова в соответствии с RFC2047 (MIME).

Более длинное объяснение:

RFC2617, раздел 2 (HTTP-аутентификация) определяет базовые учетные данные :

basic-credentials = base64-user-pass
base64-user-pass  = <base64 encoding of user-pass, 
                     except not limited to 76 char/line>
user-pass         = userid ":" password
userid            = *<TEXT excluding ":">
password          = *TEXT

Спецификацию не следует читать без ссылки на RFC2616 (HTTP 1.1) для определений в BNF (например, приведенное выше):

Эта спецификация является дополнением к спецификации HTTP / 1.1 2 . Он использует расширенный раздел 2.1 BNF этого документа и полагается как на нетерминалы, определенные в этом документе, так и на другие аспекты спецификации HTTP / 1.1.

RFC2616, раздел 2.1 определяет ТЕКСТ (выделено мной):

Правило TEXT используется только для описательного содержимого полей и значений, которые не предназначены для интерпретации парсером сообщений. Слова * TEXT МОГУТ содержать символы из наборов символов, отличных от ISO-8859-1, только при кодировании в соответствии с правилами RFC 2047.

TEXT           = <any OCTET except CTLs, but including LWS>

Так что это определенно iso-8859-1, если вы не обнаружите другую кодировку в соответствии с правилами RFC2047 (MIME pt. 3):

// Username: Mike
// Password T€ST
Mike:=?iso-8859-15?q?T€ST?=

В этом случае знак евро в слове будет закодирован в 0xA4соответствии с ISO-8859-15 . Насколько я понимаю, вы должны проверить эти закодированные разделители слов, а затем декодировать слова внутри на основе указанной кодировки. Если вы этого не сделаете, вы подумаете, что это пароль =?iso-8859-15?q?T¤ST?=(обратите внимание, что 0xA4он будет декодирован в¤ при интерпретации как iso-8859-1).

Я так понимаю, я не могу найти более явного подтверждения, чем эти RFC. И некоторые из них кажутся противоречивыми. Например, одна из 4 заявленных целей RFC2047 (MIME, pt. 3) - переопределить:

формат сообщений для ... текстовой информации заголовка в наборах символов, отличных от US-ASCII.

Но тогда RFC2616 (HTTP 1.1) определяет заголовок, используя правило TEXT, которое по умолчанию имеет значение iso-8859-1. Означает ли это, что каждое слово в этом заголовке должно быть закодированным словом (т.е.=?...?= формой)?

Также важно, что ни один текущий браузер этого не делает. Они используют utf-8 (Chrome, Opera), iso-8859-1 (Safari), системную кодовую страницу (IE) или что-то еще (например, только самый старший бит из utf-8 в случае Firefox).

Изменить: я только что понял, что этот ответ больше смотрит на проблему с точки зрения сервера.

Михиль ван Остерхаут
источник
Кодировка RFC 2047 в этом случае не применяется.
Джулиан Решке
@JulianReschke Ну, в спецификации ясно сказано: «только при кодировании в соответствии с правилами RFC 2047». Я понимаю, что правила RFC2047 могут быть неприменимы к заголовкам HTTP, но в спецификации довольно четко указано на это. Я добавил, что на самом деле ни один браузер не делает этого.
Michiel van Oosterhout
4
спецификации HTTPbis больше не будут упоминать RFC 2047.
Джулиан Решке
Очень подробное описание, спасибо @MichielvanOosterhout!
ToastyMallows 01
5

РЛК в сторону, в Spring Framework , в BasicAuthenticationFilterклассе, по умолчанию UTF-8 .

Я считаю, что причиной этого выбора является то, что UTF-8 может кодировать все возможные символы, а ISO-8859-1 (или ASCII) - нет. Попытка использовать имя пользователя / пароль с символами, не поддерживаемыми в системе, может привести к нарушению поведения или (что еще хуже) к снижению безопасности.

Holmis83
источник
1
Что ж, использование UTF-8 не поможет, если другая сторона не знает об этом. Поэтому было бы хорошо, если бы среда Spring реализовала параметр кодировки, описанный в < greenbytes.de/tech/webdav/rfc7617.html#rfc.section.2.1 >
Джулиан Решке
1
@JulianReschke Я сообщил, как это реализовано в одном из наиболее распространенных фреймворков и какова вероятная причина этого. Не стреляйте в посыльного!
holmis83
4

Если вас интересует, что делают браузеры, когда вы вводите символы, отличные от ascii, в приглашении входа в систему, я просто попробовал с Firefox.

Кажется, что он лениво конвертирует все в ISO-8859-1, беря младший байт каждого значения Unicode, например:

User: 豚 (\u8c5a)
Password: 虎 (\u864e)

Кодируются так же, как:

User: Z (\u005a)
Password: N (\u004e)

0x5a 0x3a 0x4e base64-> WjpO

anda apterus
источник
1
Да, это старое поведение Firefox. Он был изменен (кажется, в V57) и теперь использует UTF-8.
sleske
1
V59, а не V57. В настоящее время находится в стадии бета-тестирования.
Джулиан Решке