|
|
Publicado em 31/07/2023 18:36:01
|
|
|
|

Numa manhã ensolarada, eu estava sentado em frente ao meu laptop reestruturando um pouco de código em C#. Tudo está indo bem e será um dia produtivo. Depois adicionei muitos sinais iguais à sequência literal constante, e as coisas explodiram. A produtividade acabou. A calma reconstrução de domingo ficou para o fim. Até o sol decidiu se esconder atrás das nuvens.
Depois de passar de 30 a 40 minutos tentando entender o que eu estava fazendo de errado, percebi que não era comigo. É a Microsoft. Aparentemente, encontrei um bug antigo na função de decodificação do Base64.Convert.FromBase64StringEsse bug definitivamente existe desde que o .NET 1.1 foi lançado em 2003. Uau! Isso é antigo. E não é muito difícil de reproduzir. Muito bom trabalho:
Tecnicamente, isso é ilegal, Base64. A versão legal é "abc=". Note apenas um caractere de preenchimento =. A codificação Base64 representa a cada 6 bits de entrada binária em um caractere ASCII. Isso significa que cada 4 caracteres em uma string codificada em Base64 representa 3 bytes. Quando os dados codificados não são múltiplos de 3 bytes, o codificador Base64 adiciona um caractere de preenchimento para tornar o Base64 um múltiplo de 4 caracteres. Isso gerará uma string Base64 devidamente preenchida com "abc=". Adicionar outro = invalida o problema.
Base64 "abc=" é decodificado como dois bytes [105, 183]. Está correto. Adicionar outro caractere de enchimento no final não deveria realmente alterar o valor codificado. É como adicionar um espaço ao final de uma frase. Sim, está lá, mas não muda o significado da frase. Mas o .NET não acha que sim. "abc==" é decodificado como um byte [109]. Além de ficar mais curto, o que foi estranho porque fizemos a entrada mais longa. Também se tornou diferente. O primeiro byte vai de 105 para 109. E também não fez exceção. Adicione outro = e você recebe uma exceção. Incrível!
Código:
Saída:
'abc=' -> [105, 183] 'abc==' -> [109] É realmente impressionante que ninguém tenha notado isso há tantos anos. Ou foi encontrado, mas não consertado. O Base64 é muito importante na troca de informações na rede. Pode ser visto em todos os lugares. No entanto, o .NET não se livra do decodificador falho Base64 há anos.
No começo, não acreditei e comecei a investigar. Pesquisei no Google por um tempo e não encontrei muita coisa. Depois postei no StackOverflow e também não tive muita sorte. Quando entendi o que estava acontecendo, até tive que responder minhas próprias perguntas. Depois de pesquisar um tempo no GitHub, me deparei com uma correção feita no .NET Core em julho de 2018. Então, a versão mais recente do .NET Core resolve esse problema corretamente e lança uma exceção:
Exceção Não Tratada: System.FormatException: A entrada não é uma string válida em Base-64, pois contém um caractere não-base 64, mais de dois caracteres de preenchimento ou um caractere ilegal entre os Personagens de enchimento e enchimento de personagens. at System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) em System.Convert.FromBase64String(Strings s) em Program.DecodeAndPrint(String base64) em ./base64/Program.cs:linha 13 em Program.Main() em ./base64/Program.cs:linha 8 Levou cerca de 15 anos para eles encontrar e resolver o problema. Curiosamente, ninguém realmente tentou consertá-lo especificamente. Isso aconteceu quando reescreveram o código para torná-lo mais rápido:
Convert.FromBase64() apresenta um bug sutil em que o segundo caractere preenchido ilegalmente no final da string faz com que a decodificação "tenha sucesso" ao remover o penúltimo caractere.
Estamos em . Esse bug foi corrigido inadvertidamente quando a API foi otimizada no NetCore 2.1. Adicione testes aos erros de registro e certifique-se de que não voltamos para trás. Então, esse problema foi corrigido no .NET Core 2.2. Mas na versão mais recente do .NET Framework 4.7.2 ainda há problemas. Parece que também está quebrado no Mono.
A solução alternativa no .NET 4.7.2 é recarregar a string preenchida incorretamente com algo assim:
Original:O login do hiperlink está visível.
|
Anterior:Azure DevOps (viii) compila ASP.NET projetos MVC usando Pipelines BuildPróximo:Um novo temporizador no .NET 6, o PeriodicTimer, é usado
|