Que codificação devo usar para autenticação básica HTTP?

87

O RFC2617 diz para codificar o nome de usuário e a senha para base64, mas não diz qual codificação de caracteres usar ao criar os octetos para entrada no algoritmo de base64.

Devo assumir US-ASCII ou UTF8? Ou alguém já resolveu essa questão em algum lugar?

Dobes Vandermeer
fonte

Respostas:

74

Especificação original - RFC 2617

RFC 2617 pode ser lido como "ISO-8859-1" ou "indefinido". Sua escolha. É sabido que muitos servidores usam ISO-8859-1 (goste ou não) e irão falhar quando você enviar algo diferente. Portanto, provavelmente a única escolha segura é seguir o ASCII.

Para obter mais informações e uma proposta para corrigir a situação, consulte o rascunho "Um parâmetro de codificação para autenticação básica de HTTP" (que formou a base para RFC 7617).

Novo - RFC 7617

Desde 2015 existe o RFC 7617 , que torna o RFC 2617 obsoleto. Em contraste com o RFC antigo, o novo RFC define explicitamente a codificação de caracteres a ser usada para nome de usuário e senha.

  • A codificação padrão ainda está indefinida. É necessário apenas ser compatível com US-ASCII (o que significa que mapeia bytes ASCII para bytes ASCII, como o UTF-8 faz).
  • O servidor pode opcionalmente enviar um parâmetro de autenticação adicional charset="UTF-8"em seu desafio, como este:
    WWW-Authenticate: Basic realm="myChosenRealm", charset="UTF-8"
    Isso anuncia que o servidor aceitará caracteres não ASCII no nome de usuário / senha e que espera que eles sejam codificados em UTF-8 (especificamente Formulário C de normalização) . Observe que apenas UTF-8 é permitido.

Versão completa:

Leia as especificações . Se contém detalhes adicionais, como o procedimento de codificação exato e a lista de pontos de código Unicode que devem ser suportados.

Suporte de navegador

A partir de 2018, os navegadores modernos normalmente usarão UTF-8 como padrão se um usuário inserir caracteres não ASCII para nome de usuário ou senha (mesmo se o servidor não usar o charsetparâmetro).

  • O Chrome também parece usar UTF-8
  • O Internet Explorer não usa UTF-8 ( problema # 11879588 )
  • O Firefox está experimentando uma mudança atualmente planejada para a v59 ( bug 1419658 )

Reino

O parâmetro realm ainda suporta apenas caracteres ASCII, mesmo no RFC 7617.

Julian Reschke
fonte
Obrigado Julian. Eu tinha encontrado essa proposta, mas parece que expirou e não fui a lugar nenhum. Que pena :-(.
Dobes Vandermeer
1
Sua resposta deve ser a melhor. Posso parafrasear como ASCII com certeza, talvez ISO-8859-1 se você tiver sorte.
Dobes Vandermeer
Parece que a última versão 04 da proposta (que coincidentemente parece ter sido publicada hoje) expira em 1º de agosto de 2012.
Michiel van Oosterhout
A resposta era obsoleta, pois não mencionava a RFC 7617. Eu editei para incluir isso. Julian: Espero que você não se importe.
sleske
Ops - acabei de perceber que você é, na verdade, o autor do RFC 7617. Agora realmente espero não ter editado algo incorretamente.
sleske
41

Resposta curta: iso-8859-1 a menos que palavras codificadas sejam usadas de acordo com RFC2047 (MIME).

Explicação mais longa:

RFC2617, seção 2 (autenticação HTTP) define as credenciais 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

A especificação não deve ser lida sem se referir a RFC2616 (HTTP 1.1) para definições em BNF (como a acima):

Esta especificação é um complemento da especificação HTTP / 1.1 2 . Ele usa a seção BNF aumentada 2.1 desse documento e se baseia em ambos os terminais não definidos nesse documento e outros aspectos da especificação HTTP / 1.1.

RFC2616, seção 2.1 define TEXTO (grifo meu):

A regra TEXT é usada apenas para conteúdos de campo descritivos e valores que não devem ser interpretados pelo analisador de mensagens. Palavras de * TEXTO PODEM conter caracteres de conjuntos de caracteres diferentes de ISO-8859-1 apenas quando codificadas de acordo com as regras da RFC 2047.

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

Portanto, é definitivamente iso-8859-1, a menos que você detecte alguma outra codificação de acordo com as regras RFC2047 (MIME pt. 3):

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

Neste caso, o sinal do euro na palavra seria codificado de 0xA4acordo com a iso-8859-15 . É meu entendimento que você deve verificar esses delimitadores de palavras codificadas e, em seguida, decodificar as palavras internas com base na codificação especificada. Do contrário, você pensará que a senha é =?iso-8859-15?q?T¤ST?=(observe que 0xA4seria decodificada para ¤quando interpretada como iso-8859-1).

Pelo que entendi, não consigo encontrar uma confirmação mais explícita do que essas RFCs. E algumas coisas parecem contraditórias. Por exemplo, um dos 4 objetivos declarados da RFC2047 (MIME, pt. 3) é redefinir:

o formato das mensagens para permitir ... informações de cabeçalho textuais em conjuntos de caracteres diferentes de US-ASCII.

Mas então o RFC2616 (HTTP 1.1) define um cabeçalho usando a regra TEXT, cujo padrão é iso-8859-1. Isso significa que cada palavra neste cabeçalho deve ser uma palavra codificada (ou seja, a =?...?=forma)?

Também relevante, nenhum navegador atual faz isso. Eles usam utf-8 (Chrome, Opera), iso-8859-1 (Safari), a página de código do sistema (IE) ou outra coisa (como apenas o bit mais significativo de utf-8 no caso do Firefox).

Edit: Acabei de perceber que esta resposta aborda o problema mais da perspectiva do lado do servidor.

Michiel van Oosterhout
fonte
A codificação RFC 2047 não se aplica neste caso.
Julian Reschke
@JulianReschke Bem, a especificação afirma claramente "somente quando codificado de acordo com as regras da RFC 2047". Eu entendo que as regras em RFC2047 podem não ser aplicáveis ​​a cabeçalhos HTTP, mas as especificações são bem claras ao se referir a elas. Eu adicionei o fato de que nenhum navegador realmente faz isso.
Michiel van Oosterhout
4
as especificações HTTPbis não mencionarão mais o RFC 2047.
Julian Reschke
Artigo muito detalhado, obrigado @MichielvanOosterhout!
ToastyMallows 01 de
5

RFCs à parte, no framework Spring , a BasicAuthenticationFilterclasse, o padrão é UTF-8 .

Acredito que a razão para essa escolha é que UTF-8 é capaz de codificar todos os caracteres possíveis, enquanto ISO-8859-1 (ou ASCII) não é. Tentar usar nome de usuário / senha com caracteres não suportados no sistema pode levar a um comportamento quebrado ou (talvez pior) degradação da segurança.

holmis83
fonte
1
Bem, usar UTF-8 não ajuda se o outro lado não souber disso. Portanto, seria bom se o framework Spring implementasse o parâmetro charset descrito em < greenbytes.de/tech/webdav/rfc7617.html#rfc.section.2.1 >
Julian Reschke
1
@JulianReschke Eu informei como ele é implementado em um dos frameworks mais comuns e um provável motivo para isso. Não atire no mensageiro!
holmis83 de
4

Se você estiver interessado em saber o que os navegadores fazem quando você insere caracteres não ascii no prompt de login, acabei de tentar com o Firefox.

Parece converter preguiçosamente tudo para ISO-8859-1, tomando o byte menos significativo de cada valor Unicode, por exemplo:

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

São codificados da mesma forma que:

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

0x5a 0x3a 0x4e base64-> WjpO

anda aptero
fonte
1
Sim, esse é o comportamento antigo do Firefox. Ele foi alterado (no V57, ao que parece) e agora usa UTF-8.
sleske
1
V59, não V57. Atualmente em teste beta.
Julian Reschke