Um UUID numa URL impede que alguém troque /orders/1041 por /orders/1042 para ver o registro seguinte, e esconde quantos registros você tem. Ele não impede que quem já tem o link o compartilhe, nem substitui verificar quem pode ver a página. O que você paga por ele é uma URL que ninguém consegue ler em voz alta, um identificador que não ordena e um índice de mais ou menos o dobro da largura. Se compensa depende do que a URL protege.
O que um UUID numa URL realmente protege?
Um id sequencial vaza duas coisas. A primeira é a quantidade: você se cadastra, recebe o usuário 48213 e já sabe mais ou menos o tamanho do serviço. Olhe de novo uma semana depois e você sabe o ritmo de crescimento. A segunda são os vizinhos: se /invoices/1041 é seu, /invoices/1042 é de outra pessoa, e tentar não custa nada.
O segundo problema só é uma vulnerabilidade quando o servidor entrega o registro sem perguntar se você pode vê-lo. Essa falha tem nome, referência direta insegura a objetos (insecure direct object reference), e pertence à família mais ampla do controle de acesso quebrado. Um identificador aleatório não a elimina. Ele a torna muito mais difícil de explorar, porque um UUID v4 carrega 122 bits aleatórios e ninguém vai adivinhar o próximo. Como esses bits se distribuem no v4 e no v7 importa aqui, porque um v7 também diz quando o registro foi criado.
Então a afirmação correta é modesta: um id aleatório torna a enumeração inviável e esconde o seu tamanho. A correção do bug de fundo continua sendo uma verificação de permissão em toda requisição.
O que ele não protege?
- Quem tem o link. URLs são coladas em chats, ficam no histórico do navegador, são gravadas nos logs do servidor e reenviadas nos cabeçalhos
Referer. Se o UUID é a única coisa entre um estranho e a página, você não construiu um login, e sim um link que funciona para quem o tiver. - Qualquer outro lugar onde o id apareça. Um endpoint de listagem, um sitemap, uma exportação ou um e-mail que menciona dez ids acabou de entregar os dez. Ser impossível de adivinhar só ajuda se nada mais os revelar.
- A hora de criação, no v7. Os primeiros 48 bits são um relógio em milissegundos que qualquer um pode ler.
Um link não listado é uma boa escolha quando "qualquer pessoa com o link" é justamente a intenção, como num documento compartilhado. É a escolha errada para dados privados, em que a página deveria verificar uma sessão independentemente de como a URL seja.
Quanto custa?
- Não dá para dizer nem digitar. "Pedido 1041" sobrevive a uma ligação telefônica. Uma sequência de 36 caracteres com hifens não sobrevive, e um cliente lendo uma para o suporte vai errar um dígito.
- É mais largo. Um UUID são 16 bytes; uma chave inteira são 4 ou 8. Todo índice sobre a coluna e toda chave estrangeira que aponta para ela repete esses bytes. Numa tabela pequena é invisível, e ninguém consegue dizer quanto custa na sua sem medir.
- Um v4 não ordena. Dois ids não dizem qual registro veio primeiro. Um v7 ordena, ao preço de publicar a hora de criação.
- É difícil de comparar a olho. Duas linhas de log que diferem em um caractere de 36 parecem idênticas à primeira vista.
Se mesmo assim você ficar com UUIDs, o gerador de UUID pode tirar os hifens para uma forma de 32 caracteres. É mais curta de copiar, mas continua não sendo algo que uma pessoa consiga ditar, e a forma em minúsculas com hifens continua sendo a que convém guardar.
Quando um id sequencial é a melhor resposta?
Quando o registro é público de qualquer maneira. Números de artigo, números de ticket que os usuários citam de volta para você e números de nota fiscal não ganham nada por ficarem escondidos, e ganham muito por serem legíveis. Além disso, muitos regimes tributários esperam que os números de nota sigam uma sequência sem buracos, então confira o seu antes de trocá-los por sequências aleatórias.
Também funciona quando o acesso é verificado direito no servidor, porque aí um vizinho adivinhado devolve uma recusa e não um registro. O vazamento que sobra é a quantidade, que só importa se o seu volume é algo que você prefere manter privado.
Quais são as opções intermediárias?
- Dois ids. Mantenha um inteiro pequeno como chave primária interna e adicione uma segunda coluna com um id público aleatório. O banco de dados mantém o índice estreito e ordenado, e a URL carrega o aleatório. O custo é um índice único extra e uma busca pelo id público.
- Um token aleatório curto. Dez caracteres de um alfabeto de 32 símbolos são 50 bits. Com um milhão de registros, um único palpite às cegas acerta um deles mais ou menos uma vez a cada bilhão de tentativas, o que é ótimo quando as requisições têm limite de frequência e inútil quando não têm. Base32 é a escolha habitual de alfabeto porque sobrevive a ser lido em voz alta e digitado à mão.
- Um slug legível mais um id.
/articles/how-leap-years-work-1041é amigável para pessoas e para buscadores e não protege nada. Um gerador de slugs cobre a parte do texto; o que faz um bom slug cobre o resto.
Um atalho a evitar: bibliotecas que codificam um inteiro numa sequência de aparência aleatória. Elas são ofuscação reversível, não um segredo, então trate-as como algo cosmético.
Uma ferramenta consegue me dizer se minhas URLs são seguras?
Não, e vale ser claro sobre isso. O gerador de UUID cria identificadores v4 ou v7 no seu navegador e o inspetor dele lê a versão e, num v7, a hora de criação a partir dos bits. Ele não enxerga o seu servidor, então não consegue dizer se um endpoint verifica a propriedade do registro, se uma página de listagem vaza os ids ou se a sua fonte de aleatoriedade é sólida. Essa verificação é um teste que você faz contra a sua própria aplicação, logado como um usuário e pedindo o registro de outro.
Se você está pesando um id aleatório contra um contador, o gerador de UUID faz os dois tipos mil por vez para você ver o tamanho do resultado numa rota de verdade antes de decidir. Ele roda no seu navegador e nada do que você gerar é enviado a lugar nenhum.
E se o que você quer, no fundo, é um link que só uma pessoa deveria abrir, como enviar uma senha a alguém com segurança explica a diferença entre um link impossível de adivinhar e um segredo entregue do jeito certo.
Perguntas frequentes
É seguro colocar um UUID numa URL?
É seguro contra tentativas de adivinhar: um UUID v4 tem 122 bits aleatórios, então ninguém consegue percorrer os seus registros trocando o id. Não é seguro como substituto de um login, porque qualquer um que tenha a URL pode abri-la, e URLs vazam por logs, histórico e cabeçalhos Referer. Verifique as permissões no servidor independentemente de como o id seja.
Devo usar ids sequenciais ou UUIDs nas URLs?
Use ids sequenciais quando o registro é público ou as pessoas precisam citá-lo, e o acesso é verificado no servidor de qualquer forma. Use ids aleatórios quando a quantidade de registros é algo que você quer manter privado, ou quando uma permissão esquecida exporia os registros vizinhos. Muitos sistemas mantêm os dois: um inteiro dentro do banco de dados e um id público aleatório na URL.
Um UUID evita bugs de referência direta insegura a objetos?
Não. Ele os torna muito mais difíceis de explorar, porque um atacante não consegue adivinhar o id de outro registro, mas o bug é uma verificação de permissão ausente e continua lá. Se um UUID vaza por uma página de listagem, um e-mail ou um print compartilhado, o registro fica aberto para quem o encontrar.
Por que UUIDs são ruins para URLs legíveis?
Um UUID são 36 caracteres de hexadecimal e hifens que ninguém consegue ler em voz alta, memorizar ou comparar de relance. Um cliente que o cite por telefone vai errar. Se as pessoas precisam se referir ao registro, dê a ele um número curto pensado para humanos ou um slug legível ao lado do UUID.
Qual o tamanho necessário de um id aleatório numa URL?
O suficiente para que adivinhar às cegas seja inútil, dada a quantidade de tentativas que você permite. Dez caracteres de um alfabeto de 32 símbolos são 50 bits, cerca de um acerto a cada bilhão de tentativas contra um milhão de registros. Isso só vale se você limitar a frequência das requisições, e não diz nada sobre quem pode ver a página.
Última atualização 28 de setembro de 2026