¿Qué codificación debo usar para la autenticación básica HTTP?

Respuestas:

72

Especificaciones originales - RFC 2617

RFC 2617 se puede leer como "ISO-8859-1" o "indefinido". Tu elección. Se sabe que muchos servidores usan ISO-8859-1 (te guste o no) y fallarán cuando envíes algo más. Así que probablemente la única opción segura sea ceñirse a ASCII.

Para obtener más información y una propuesta para solucionar la situación, consulte el borrador "Un parámetro de codificación para la autenticación básica HTTP" (que formó la base de RFC 7617).

Nuevo - RFC 7617

Desde 2015 existe el RFC 7617 , que deja obsoleto el RFC 2617. A diferencia del antiguo RFC, el nuevo RFC define explícitamente la codificación de caracteres que se utilizará para el nombre de usuario y la contraseña.

  • La codificación predeterminada aún no está definida. Solo se requiere que sea compatible con US-ASCII (lo que significa que asigna bytes ASCII a bytes ASCII, como lo hace UTF-8).
  • El servidor puede enviar opcionalmente un parámetro de autenticación adicional charset="UTF-8"en su desafío, como este:
    WWW-Authenticate: Basic realm="myChosenRealm", charset="UTF-8"
    Esto anuncia que el servidor aceptará caracteres no ASCII en el nombre de usuario / contraseña, y que espera que estén codificados en UTF-8 (específicamente Normalization Form C) . Tenga en cuenta que solo se permite UTF-8.

Versión completa:

Lea la especificación . Si contiene detalles adicionales, como el procedimiento de codificación exacto y la lista de puntos de código Unicode que deben admitirse.

Soporte de navegador

A partir de 2018, los navegadores modernos generalmente usarán UTF-8 de forma predeterminada si un usuario ingresa caracteres no ASCII para el nombre de usuario o la contraseña (incluso si el servidor no usa el charsetparámetro).

  • Chrome también parece usar UTF-8
  • Internet Explorer no usa UTF-8 ( problema # 11879588 )
  • Firefox está experimentando con un cambio planeado actualmente para v59 ( error 1419658 )

Reino

El parámetro de reino todavía solo admite caracteres ASCII incluso en RFC 7617.

Julian Reschke
fuente
Gracias Julian. Me encontré con esa propuesta, pero parece que ha expirado y no he ido más lejos. Lástima :-(.
Dobes Vandermeer
1
Tu respuesta debe ser la mejor. Puedo parafrasearlo como ASCII con seguridad, tal vez ISO-8859-1 si tienes suerte.
Dobes Vandermeer
Parece que la última versión 04 de la propuesta (que coincidentemente parece ser publicada hoy) vence el 1 de agosto de 2012.
Michiel van Oosterhout
La respuesta era obsoleta, ya que no mencionaba RFC 7617. Edité para incluir esto. Julian: Espero que no te importe.
sleske
Vaya, me acabo de dar cuenta de que en realidad eres el autor de RFC 7617. Ahora realmente espero no haber editado mal algo.
sleske
41

Respuesta corta: iso-8859-1 a menos que se utilicen palabras codificadas de acuerdo con RFC2047 (MIME).

Explicación más larga:

RFC2617, sección 2 (Autenticación HTTP) define las credenciales básicas :

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

La especificación no debe leerse sin consultar RFC2616 (HTTP 1.1) para obtener definiciones en BNF (como la anterior):

Esta especificación es un complemento de la especificación HTTP / 1.1 2 . Utiliza la sección 2.1 de BNF aumentada de ese documento y se basa tanto en los no terminales definidos en ese documento como en otros aspectos de la especificación HTTP / 1.1.

RFC2616, sección 2.1 define TEXTO (énfasis mío):

La regla TEXT solo se utiliza para valores y contenidos de campos descriptivos que no están destinados a ser interpretados por el analizador de mensajes. Las palabras * TEXT PUEDEN contener caracteres de conjuntos de caracteres distintos de ISO-8859-1 solo cuando se codifican de acuerdo con las reglas de RFC 2047.

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

Entonces, definitivamente es iso-8859-1 a menos que detecte alguna otra codificación de acuerdo con las reglas RFC2047 (MIME pt. 3):

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

En este caso, el signo del euro en la palabra se codificaría 0xA4según iso-8859-15 . Tengo entendido que debe verificar estos delimitadores de palabras codificadas y luego decodificar las palabras internas según la codificación especificada. Si no lo hace, pensará que la contraseña es =?iso-8859-15?q?T¤ST?=(observe que 0xA4se decodificará ¤cuando se interprete como iso-8859-1).

Este es mi entendimiento, no puedo encontrar una confirmación más explícita que estas RFC. Y algo de eso parece contradictorio. Por ejemplo, uno de los 4 objetivos declarados de RFC2047 (MIME, punto 3) es redefinir:

el formato de los mensajes para permitir ... información de encabezado textual en juegos de caracteres que no sean US-ASCII.

Pero luego RFC2616 (HTTP 1.1) define un encabezado usando la regla TEXT que por defecto es iso-8859-1. ¿Significa eso que cada palabra en este encabezado debe ser una palabra codificada (es decir, la =?...?=forma)?

También es relevante, ningún navegador actual hace esto. Usan utf-8 (Chrome, Opera), iso-8859-1 (Safari), la página de códigos del sistema (IE) o algo más (como solo el bit más significativo de utf-8 en el caso de Firefox).

Editar: Me acabo de dar cuenta de que esta respuesta analiza el problema más desde la perspectiva del lado del servidor.

Michiel van Oosterhout
fuente
La codificación RFC 2047 no se aplica en este caso.
Julian Reschke
@JulianReschke Bueno, la especificación establece claramente "solo cuando se codifica de acuerdo con las reglas de RFC 2047". Entiendo que las reglas en RFC2047 pueden no ser aplicables a los encabezados HTTP, pero la especificación es bastante clara al referirse a ellas. He añadido el hecho de que ningún navegador hace esto.
Michiel van Oosterhout
4
las especificaciones HTTPbis ya no mencionarán RFC 2047.
Julian Reschke
Escrito muy detallado, ¡gracias @MichielvanOosterhout!
ToastyMallows
5

Dejando a un lado las RFC, en Spring Framework , la BasicAuthenticationFilterclase, el valor predeterminado es UTF-8 .

Creo que la razón de esta elección es que UTF-8 es capaz de codificar todos los caracteres posibles, mientras que ISO-8859-1 (o ASCII) no lo es. Intentar utilizar un nombre de usuario / contraseña con caracteres no admitidos en el sistema puede provocar un comportamiento defectuoso o (quizás peor) una seguridad degradada.

holmis83
fuente
1
Bueno, usar UTF-8 no ayuda si la otra parte no lo sabe. Por lo tanto, sería bueno si el marco de Spring implementara el parámetro de juego de caracteres descrito en < greenbytes.de/tech/webdav/rfc7617.html#rfc.section.2.1 >
Julian Reschke
1
@JulianReschke Informé cómo se implementa en uno de los marcos más comunes y una probable razón para ello. ¡No dispares al mensajero!
holmis83
4

Si está interesado en lo que hacen los navegadores cuando ingresa caracteres no ascii en el indicador de inicio de sesión, acabo de probar con Firefox.

Parece convertir perezosamente todo a ISO-8859-1 tomando el byte menos significativo de cada valor Unicode, por ejemplo:

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

Están codificados de la misma manera que:

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

0x5a 0x3a 0x4e base64-> WjpO

anda apterus
fuente
1
Sí, ese es el antiguo comportamiento de Firefox. Se cambió (en V57, al parecer) y ahora usa UTF-8 en su lugar.
sleske
1
V59, no V57. Actualmente en prueba beta.
Julian Reschke