Decodificar URL

Cole uma URL ou um valor e leia o que está escrito debaixo das sequências de porcentagem. A única ambiguidade real é oferecida como escolha: se o sinal de mais é um espaço, como num query string de formulário, ou um mais de verdade, como num caminho. Nada é enviado, e isso importa porque as URLs que se colam aqui vêm de logs e carregam identificador de sessão ao lado.

Query strings de formulário HTML escrevem espaço como +. Num caminho, um mais é um mais.

Resultado

A resposta aparece aqui enquanto você digita.

  • Onde roda

    Nada é enviado, porque não há arquivo — a conta é feita nesta página.

  • Sem fila, sem conta

    Responde na velocidade da sua máquina e nunca pergunta quem você é.

  • Quantas vezes quiser

    Nada é contado nem limitado — responder de novo não nos custa nada.

Como funciona

  1. Cole a URL ou o valor codificado.
  2. Escolha como tratar o sinal de mais, conforme a origem da string.
  3. Leia o resultado. Nada foi enviado.

O sinal de mais é a única decisão de verdade

Um `+` num query string quase sempre significa espaço, porque é assim que um formulário HTML escreve. Num caminho, não: ali é um caractere de mais, literal. A mesma string, portanto, é lida de dois jeitos conforme a parte da URL de onde ela veio.

A consequência que morde são os valores com um mais de verdade dentro: telefone em formato internacional e e-mail com subendereço. Um `[email protected]` lido com a regra de formulário vira `ana [email protected]`, e a falha aparece na entrega, onde ninguém mais liga uma coisa à outra.

Bytes, e não caracteres

Cada `%` seguido de dois dígitos hexadecimais é um byte, e caracteres fora do ASCII ocupam vários: `%C3%A7` é um cedilha, `%C3%A3` é um `ã`, e um emoji são quatro sequências seguidas. Decodificar consiste em juntar os bytes e depois lê-los como UTF-8.

Por isso uma sequência solta pode ser inválida mesmo com os dígitos corretos. Um `%E7` sozinho era um cedilha em Latin-1 e não é UTF-8 válido; aqui isso é dito em vez de devolver um símbolo de substituição que pareceria o resultado. Ver essa sequência é a pista de que o valor foi gerado por uma ferramenta anterior ao UTF-8.

A dupla codificação aparece na hora de decodificar

Se depois de decodificar ainda sobram sequências de porcentagem, a string estava codificada duas vezes. Esse é o resultado correto: uma passada converte `%2520` em `%20`, e uma ferramenta que continuasse decodificando até não sobrar nada destruiria os valores que contêm um `%` de verdade.

A solução não é passar rotineiramente duas vezes por aqui, e sim encontrar na sua esteira a etapa que codifica algo já codificado — quase sempre um framework que faz por você e um template que repete.

Decodificar uma URL inteira pode quebrá-la

Se você decodifica um endereço completo, os `%2F` viram barras e os `%3F` viram interrogações, e o resultado deixa de ter a mesma estrutura: o que era um valor passa a parecer um caminho ou um query string novo.

Isso é útil para ler e perigoso para reutilizar. Um redirecionamento aberto é construído exatamente assim — o atacante coloca uma URL codificada como valor e alguma coisa decodifica antes de conferir. A regra é decodificar para olhar e validar sempre a forma original.

O fragmento não vem nos logs

Se você está lendo uma URL de um log de servidor, tudo o que vinha depois do `#` não está ali: o navegador nunca envia. O endereço que você vê está incompleto por desenho, e isso explica mais de um caso em que um parâmetro «some» entre o que a pessoa tinha e o que ficou registrado.

Numa exportação de estatística ele pode aparecer, porque ali quem escreve é um script que enxerga o fragmento. Saber de qual fonte veio a string que você está olhando muda o que dá para concluir dela, e é o tipo de detalhe que economiza uma hora de confusão.

O que costuma haver dentro de um parâmetro

Termos de busca, destinos de redirecionamento, e-mails, tokens de confirmação e parâmetros UTM. Os três primeiros são dado pessoal com bastante frequência, e o quarto é uma credencial de uso único.

Estarem codificados não protege nada: a codificação de porcentagem é legível para qualquer pessoa, e aquela string está no log do servidor, no histórico do navegador e no cabeçalho de referrer do clique seguinte. Se aqui aparecer algo com cara de segredo, esse é o achado — não o fato de ter dado para decodificar.

Os parâmetros UTM e por que são inofensivos

`utm_source`, `utm_medium`, `utm_campaign`, `utm_term` e `utm_content` vêm do Urchin, a ferramenta que deu origem ao Google Analytics. Eles não fazem nada no servidor: são texto que um script de medição lê no navegador.

Como não fazem nada, podem ser removidos sem consequência ao repassar um link, se você não quiser misturar a estatística de quem te mandou com o seu repasse. E, como viajam no endereço, acabam em histórico, em link compartilhado e em favorito — a razão de alguns links de newsletter serem absurdamente longos.

Uma sequência cortada no fim da linha

Log tem limite de tamanho de campo, e uma linha longa é cortada onde o limite manda, não onde faria sentido. Uma URL truncada no meio de uma sequência termina com um `%C3` sem par ou com um `%2` sem o segundo dígito, e não existe saída correta para isso.

Aqui isso é relatado como sequência malformada em vez de ser completado com um chute. A informação útil é a posição: se o problema está exatamente no último caractere da entrada, você não tem uma string estragada, tem uma string cortada, e a correção é aumentar o campo na origem.

O %00 e outras coisas que não deveriam estar num valor

Um `%00` decodifica para um byte zero, que em C termina uma string. Foi essa a base de uma família inteira de ataques: um valor cuja verificação enxerga uma coisa e cuja abertura de arquivo enxerga outra, porque as duas camadas discordam sobre onde a string acaba.

A maioria das linguagens modernas não é vulnerável a isso, e mesmo assim ver um `%00`, um `%0d` ou um `%0a` num parâmetro continua sendo um sinal. Quebra de linha codificada dentro de um valor que vai virar cabeçalho HTTP é como se injeta um cabeçalho novo, e é a razão de um servidor rejeitar esses bytes em vez de repassá-los.

Aqui não há prévia e nada é aberto

Aqui se decodifica e não se visita. Não há requisição ao host, não há resolução de redirecionamento e não há prévia, e isso é uma decisão: quem está examinando uma URL suspeita é a última pessoa que quer que a ferramenta a abra.

Abrir ainda entregaria alguma coisa. A requisição sairia de um servidor, o IP e o horário dele ficariam no log do outro lado, e com um endereço de uso único — um link de confirmação, uma redefinição de senha — ela gastaria o link no caminho.

As sequências que nunca precisaram existir

Um `%41` decodifica para a letra `A`, e nada numa URL exigia que aquele `A` fosse escapado. Sequências assim aparecem quando alguma ferramenta codifica muito além do necessário, e são inofensivas na leitura: o resultado é o mesmo texto.

Elas deixam de ser inofensivas quando alguma coisa no meio do caminho compara a string antes de decodificar. Um filtro que procura uma palavra literal não a encontra se ela estiver escrita com sequências de porcentagem, enquanto o servidor no fim da linha decodifica e a usa. É a razão pela qual uma verificação de segurança precisa acontecer sobre a forma decodificada e normalizada, nunca sobre a string crua.

Linha de log colada aqui, e a LGPD

URLs de log e de exportação de estatística carregam com frequência dado pessoal: termo de busca, e-mail como parâmetro, identificador associável a uma conta. Como aqui a decodificação acontece na página, nada disso é compartilhado conosco.

É o que torna possível olhar esse tipo de exportação com uma ferramenta online. Um serviço que decodificasse remotamente teria recebido a linha e a teria nos logs dele — exatamente a hipótese que a maioria das políticas internas existe para impedir.

Decodificar URL: perguntas frequentes

Devo tratar o + como espaço?

Se a string veio de um query string, quase certamente sim: formulários HTML escrevem espaço como +. Se veio de um caminho, não, porque ali um mais é um mais. Por isso é uma escolha e não uma suposição.

Depois de decodificar ainda sobram %20, por quê?

Porque a string estava codificada duas vezes: ela continha %2520. Esse é o resultado correto de uma passada. O que precisa ser corrigido é a etapa da sua esteira que codifica algo já codificado.

Por que uma sequência que parece correta falha?

Porque os bytes que ela forma não são UTF-8 válido. Um %E7 sozinho era um cedilha em Latin-1 e aqui não é. Isso é dito em vez de devolver um símbolo de substituição que pareceria um resultado.

O endereço é aberto?

Não. Ele é decodificado, não visitado: não há requisição ao host, nem prévia, nem resolução de redirecionamento. Com uma URL suspeita ou de uso único, é justamente isso que importa.

A string sai do meu aparelho?

Não. Ela é decodificada nesta página. Isso conta porque URLs tiradas de log carregam ao lado identificador de sessão, token e às vezes e-mail.

Outras ferramentas