Codificação, escape e hash
Base64 não é criptografia, btoa não é UTF-8, encodeURI não é encodeURIComponent e SHA-256 não é um hash de senha. Aqui está o que cada um deles realmente faz e os erros específicos que decorrem da suposição do contrário.
Codificação não é criptografia e não é compactação
A codificação altera a forma como os dados são gravados. A criptografia altera quem pode lê-la. A compactação altera a quantidade de espaço necessária. Esses são três trabalhos diferentes, e o base64 executa apenas o primeiro – mal, se você esperava por qualquer um dos outros dois.
Base64 pega três bytes por vez e os reescreve como quatro caracteres extraídos de um alfabeto de símbolos 64. Quatro caracteres carregando três bytes significam que a saída é sempre cerca de 33% maior que a entrada, mais preenchimento. Ele existe porque uma grande parte da infraestrutura – cabeçalhos de e-mail, cabeçalhos HTTP, valores de string JSON, URLs, atributos XML – foi projetada para texto e manipula ou rejeita bytes arbitrários. Base64 é o adaptador que permite enviar bytes através de um canal em forma de texto.
Qualquer um pode reverter instantaneamente, sem chave, porque não há chave. Se você base64 uma senha, você publicou a senha em um formato um pouco inconveniente. Isso é importante porque a saída base64 parece embaralhada ao olho humano, que é exatamente a propriedade que faz as pessoas confiarem nela para coisas que ela não pode fazer.
Por que btoa() quebra e as duas maneiras diferentes de quebrar
O navegador fornece btoa() e atob(), e eles são mais antigos que as APIs de texto modernas. btoa é definido sobre "strings binárias": strings em que cada unidade de código é um único byte, de 0 a 255. Texto não é isso.
A primeira falha é alta. Chame btoa("世界") e você obterá um InvalidCharacterError, porque U+4E16 não cabe em um byte. Falhas gritantes são do tipo bom – você as percebe imediatamente e sai em busca de uma solução.
A segunda falha é silenciosa e é a que chega à produção. O caractere é é U+00E9, que cabe em um byte. Então btoa("café") retorna felizmente, codificando é como o byte único 0xE9. Mas é em UTF-8 tem dois bytes, 0xC3 0xA9. A base64 que você acabou de produzir decodifica, em todos os outros sistemas do planeta, para algo que não é o seu texto. Você descobrirá semanas depois quando um nome em um banco de dados se transformou em um caractere substituto.
A solução é parar de tratar o texto como bytes e convertê-lo explicitamente. TextEncoder produz os bytes UTF-8; codifique-os. TextDecoder transforma bytes de volta em texto, e construí-lo com { fatal: true } faz com que ele lance sequências inválidas em vez de substituir silenciosamente U+FFFD, então uma decodificação que não pode estar correta falha em vez de retornar um absurdo de aparência plausível. Esse é o pipeline que este kit de ferramentas usa, e é por isso que emoji, combinando marcas e scripts da direita para a esquerda, tudo de ida e volta.
- Converta texto em bytes com TextEncoder - nunca indexe na string.
- Codifique os bytes para base64.
- Para reverter: decodifique base64 em bytes e, em seguida, decodifique os bytes como UTF-8 com fatal: true.
- Se a etapa UTF-8 falhar, a carga será binária, não texto. Mostre-o como hexadecimal em vez de fingir.
base64 versus base64url e a questão do preenchimento
Base64 padrão usa + e / como seus dois últimos símbolos. Ambos são significativos em URLs: + pode ser lido como um espaço codificado em strings de consulta e / é um separador de caminho. Portanto, RFC 4648 define um segundo alfabeto, base64url, que substitui - e _. Os JWTs o utilizam, assim como a maioria dos formatos de token e muitas APIs.
O preenchimento é a outra variável. Pads base64 padrão com = então o comprimento de saída é sempre um múltiplo de quatro. base64url geralmente elimina o preenchimento, porque = é em si um caractere estranho em um URL e o comprimento pode ser recuperado aritmeticamente. Um decodificador que insiste no preenchimento rejeitará segmentos JWT perfeitamente válidos.
Conselho prático: seu decodificador deve aceitar ambos os alfabetos e tolerar a falta de preenchimento, porque você raramente controla o que recebe. Seu codificador deve ser explícito sobre o que emite, porque o destinatário provavelmente se importa. O utilitário base64 aqui faz exatamente isso – aceita qualquer coisa razoável e permite escolher precisamente o que produz.
encodeURI e encodeURIComponent: a diferença em uma frase
Ambos codificam por cento usando UTF-8. Eles diferem apenas em quais caracteres eles deixam de lado, e essa diferença é toda a história: encodeURIComponent escapa dos delimitadores reservados, encodeURI não.
Os delimitadores reservados são os caracteres que dão a URL sua estrutura: : / ? #[ ]@ ! $ & ' ( ) * + , ; =. encodeURI assume que você entregou a ele um URL que já está estruturado corretamente e deve permanecer assim, então os preserva - não transformará https:// em https%3A%2F%2F. encodeURIComponent assume que você entregou a ele uma peça que será colocada em um slot, então ele escapa deles, garantindo que a peça não possa sair de seu slot.
O bug que isso produz é completamente mecânico. Tome um valor de pesquisa de a&b=c. Codifique-o com encodeURI e anexe-o como ?q=a&b=c, e você terá criado silenciosamente dois parâmetros: q agora é apenas "a" e um b=c perdido apareceu. Codifique-o com encodeURIComponent e você obterá ?q=a%26b%3Dc, um parâmetro, valor correto. A mesma classe de bug permite que um valor criado injete parâmetros em um URL que seu código constrói - e é por isso que "usar o formulário do componente para valores" é uma regra de segurança, não apenas uma regra de correção.
A codificação de formulário é uma terceira regra que se parece com a segunda. application/x-www-form-urlencoded grava um espaço como + em vez de %20. Se você decodificar o corpo de um formulário com decodeURIComponent simples, cada sinal de mais nos dados se tornará um espaço. Cada caixa de pesquisa que já transformou "C++" em "C" é esse bug.
HTML entidades e por que decodificá-las com innerHTML é um mau hábito
Escapar para HTML é estreito e bem compreendido: & torna-se &, < torna-se <, > torna-se >, e dentro dos valores dos atributos " e ' também precisa escapar. Cinco caracteres. Escapar mais do que isso - transformar cada letra acentuada em uma entidade nomeada - foi uma solução alternativa para os dias de codificações de caracteres incertas e agora é um estilo opcional em vez de segurança.
A decodificação é onde mora o mau hábito. O truque de uma linha que aparece em todas as respostas é atribuir a string ao innerHTML de um elemento desanexado e ler seu textContent. Funciona e é uma má ideia. Você entregou uma entrada não confiável ao analisador HTML, que constrói nós DOM reais a partir dela. Um <img src=x onerror=...> nessa string se torna um elemento de imagem real com um manipulador de erros real anexado; se essa subárvore for inserida no documento, ela será executada. Ele também destrói silenciosamente seus dados: as tags na entrada desaparecem em vez de circularem, porque o analisador as interpretou como marcação em vez de texto.
A decodificação adequada de entidades não precisa de nenhum analisador: combine a referência, procure o nome em uma tabela ou faça a aritmética para uma referência numérica. São algumas dezenas de linhas, ele não pode executar nada e faz ida e volta fielmente. Este kit de ferramentas faz isso dessa maneira, e é por isso que colar uma tag de script no decodificador de entidade mostra uma tag de script.
Escolhendo um hash e as três questões que o decidem
Um hash criptográfico transforma qualquer entrada em um resumo de comprimento fixo, de modo que encontrar duas entradas com o mesmo resumo seja inviável. Essa propriedade é o que permite que um resumo substitua os dados – em uma assinatura, uma verificação de integridade ou um endereço de conteúdo.
Primeira pergunta: você está se protegendo contra um acidente ou contra um adversário? Uma soma de verificação que protege contra um download corrompido só precisa capturar movimentos aleatórios; CRC32 está bem. Um resumo de que um invasor pode se beneficiar com a colisão precisa de um hash que ainda esteja em pé. Essa distinção é a razão pela qual SHA-1 não é simplesmente "antigo".
SHA-1 está quebrado, concretamente. Em 2017 o trabalho SHAttered produziu dois arquivos PDF diferentes com o mesmo resumo SHA-1. Em 2020, "SHA-1 is a Shambles" demonstrou uma colisão de prefixo escolhido - a variante mais forte e muito mais perigosa, porque permite que um invasor colida dois documentos significativamente diferentes, em vez de dois blobs cuidadosamente construídos. Se a segurança de um sistema depende da resistência à colisão SHA-1, essa segurança desaparece. SHA-1 permanece neste kit de ferramentas porque os IDs de objetos git e uma longa cauda de assinaturas API herdadas ainda o utilizam, e você precisa ser capaz de reproduzir esses valores. Reproduzir um valor não é o mesmo que confiar nele.
Segunda pergunta: a entrada é uma senha? Se assim for, nada disso é a resposta. SHA-256 foi projetado para ser rápido, e rápido é exatamente errado para senhas: significa que um invasor em seu banco de dados pode tentar bilhões de tentativas por segundo. As senhas precisam de uma função deliberadamente lenta e com muita memória, com um salt por usuário – Argon2id, scrypt ou bcrypt. Isto não é uma nuance; usar SHA-256 para senhas é o erro grave de hash mais comum.
Terceira pergunta: você precisa de um resumo codificado? Se você estiver autenticando uma mensagem em vez de tirar suas impressões digitais, você deseja HMAC, não um hash simples. Concatenar um segredo e fazer hash é um gol contra clássico contra ataques de extensão de comprimento; HMAC existe porque essa construção é mais difícil de acertar do que parece.
Para todo o resto - impressão digital de um arquivo, um endereço de conteúdo, um atributo de integridade - SHA-256 é o padrão sensato e SHA-512 geralmente é mais rápido em hardware de 64 bits, ao mesmo tempo que fornece um resumo mais amplo.
Por que os hashes aqui vêm do navegador
Os resumos neste kit de ferramentas são computados pelo SubtleCrypto, a implementação do Web Crypto do próprio navegador, e não pelo JavaScript enviado deste site. Essa é uma escolha deliberada: a implementação do navegador é auditada, mantida e geralmente executada como código nativo otimizado. Um SHA-256 escrito à mão em um pacote de páginas é mais código para confiar sem nenhum benefício.
Tem uma consequência visível. Web Crypto só é exposto em um contexto seguro, ou seja, https:// ou localhost. Abra esta página sobre HTTP simples em um endereço LAN e crypto.subtle será indefinido, então o utilitário hash lhe dirá isso claramente, em vez de falhar silenciosamente ou substituir algo mais fraco.
O mesmo raciocínio impulsiona o gerador UUID. crypto.randomUUID() também é apenas de contexto seguro, portanto, quando não estiver disponível, o kit de ferramentas volta para crypto.getRandomValues() - que ainda é a mesma fonte criptograficamente segura - e define a versão e os próprios bits da variante. O que isso nunca fará é voltar para Math.random(). Esse é um PRNG rápido e não criptográfico cujo estado interno pode ser recuperado a partir de uma curta execução de suas saídas, e os identificadores têm o infeliz hábito de serem promovidos em chaves de sessão e links de redefinição de senha. Se não existir nenhuma fonte segura, esta ferramenta não gera nada e diz o porquê.
O que acontece com o que você cola
- Cada conversão, hash, decodificação e comparação é executada na guia do seu navegador. Nenhuma entrada é carregada, registrada ou armazenada em um servidor, porque não há nenhum servidor envolvido depois que a página é carregada.
- Hashes vêm da implementação de criptografia da Web do próprio navegador e UUIDs de seu gerador aleatório criptograficamente seguro. Nenhum dos dois envolve uma chamada de rede.
- Nada do que você digita é gravado no armazenamento local ou em um cookie. Recarregar a página a descarta; fechar a guia a descarta.
- A análise de todo o site é executada apenas no host de produção canônico configurado e é divulgada na Política de Privacidade; hosts locais e de visualização recusam. Valores colados, tokens, URLs e conteúdos de arquivos são excluídos dos próprios eventos analíticos de ToolAcre. A publicidade está desativada na configuração atual.
- Dito isto: uma chave JWT ou API é uma credencial ativa. O hábito seguro é nunca colar um em uma página da web que você não escreveu, por mais confiáveis que sejam suas afirmações – incluindo esta.
Questões
Base64 é uma forma de ocultar dados?
Não. É uma representação de texto reversível e sem chave, decodificável por qualquer pessoa em uma fração de segundo. Faz com que os dados sobrevivam a canais somente de texto; não torna isso secreto. Qualquer coisa genuinamente sensível precisa de criptografia, e o resultado criptografado geralmente é codificado em base64 para transporte – o que é a fonte da confusão.
Por que minha base64 é maior que a entrada?
Como quatro caracteres de saída carregam três bytes de entrada, a saída tem aproximadamente 4/3 o tamanho, mais até dois caracteres de preenchimento. Isso é inerente ao formato. Se o tamanho for importante, compacte antes da codificação - nunca depois, porque a saída base64 compacta mal.
Qual função de codificação URL devo usar?
Use encodeURIComponent para qualquer parte única que você estiver inserindo em um URL: um valor de consulta, um segmento de caminho, um fragmento. Use encodeURI somente quando você tiver um URL completo e já estruturado que contém apenas espaços ou não ASCII. Se você estiver criando uma string de consulta, prefira URLSearchParams, que aplica a regra correta para você e trata a diferença de espaço como mais.
Por que meu decodificador lança "URI malformado"?
Porque% na entrada não é seguido por dois dígitos hexadecimais. Normalmente, o texto contém um sinal de porcentagem literal — "50% off" — que nunca foi codificado. Uma porcentagem literal deve ser escrita como %25. O utilitário URL aqui relata a posição exata do escape ofensivo em vez de apenas recusar.
Posso usar SHA-256 para armazenar senhas?
Não. SHA-256 é rápido por design, o que significa que um invasor que roube seu banco de dados pode testar bilhões de senhas candidatas por segundo em hardware comum. As senhas precisam de uma função lenta, com muita memória e salgada: Argon2id, scrypt ou bcrypt. Este é o erro grave mais comum nesta área.
Por que SHA-1 ainda está aqui se está quebrado?
Porque você ainda precisa reproduzir valores SHA-1 que já existem: ids de objetos git, impressões digitais antigas de certificados TLS, assinaturas de solicitação API herdadas. Ser capaz de calcular um valor para interoperabilidade é diferente de depender dele para segurança. Cada lugar SHA-1 que aparece neste kit de ferramentas é rotulado de acordo.
Por que duas ferramentas fornecem hashes diferentes para o mesmo texto?
Quase sempre uma diferença nos bytes, não no algoritmo. Os culpados usuais são uma nova linha final (um arquivo termina com um; uma caixa de texto pode não), uma codificação de texto diferente ou CRLF versus finais de linha LF. Esta ferramenta faz o hash dos UTF-8 bytes exatamente do que você digitou e mostra a contagem de bytes, o que geralmente torna a discrepância óbvia.
Limitações
- A tabela de entidades nomeada HTML cobre o subconjunto prático — caracteres críticos de marcação, tipografia, moeda, setas, matemática, grego e latim-1 — nem todas as referências nomeadas de 2,231 HTML5. Nomes não reconhecidos são relatados e deixados exatamente como estão escritos, em vez de serem adivinhados.
- A decodificação de entidade requer o ponto e vírgula final. HTML5 tolera um punhado de referências legadas sem uma, mas decodificá-las corretamente depende do contexto de marcação circundante, que uma ferramenta de texto independente não possui.
- A geração de hash e UUID precisa de um contexto seguro (https:// ou localhost) porque o Web Crypto não é exposto de outra forma. A ferramenta relata isso em vez de substituí-la por uma implementação mais fraca.
- Apenas SHA-1, SHA-256, SHA-384 e SHA-512 estão disponíveis, porque são isso que o SubtleCrypto implementa. MD5 está ausente por escolha e também por necessidade.
- Não há HMAC, nenhuma derivação de chave e nenhuma criptografia aqui. Eles precisam de gerenciamento de chaves, algo que uma página que você encontrou na internet não deveria cuidar.
- Tudo é limitado pela memória do seu dispositivo, já que tudo roda em uma aba do navegador. As entradas são limitadas – alguns megabytes por utilitário – e a ferramenta recusa trabalhos superdimensionados em vez de congelar.