Nos últimos anos, tem se espalhado a ideia de que usar UUIDs como chave primária em tabelas de banco de dados é uma opção mais segura do que IDs sequenciais. Quando questionados sobre essa segurança, muitos desenvolvedores não conseguem explicar exatamente onde está essa vantagem. Nesse artigo, vamos desmitificar essa crença e entender quando faz sentido usar UUID e quando ele mais atrapalha do que ajuda.
O que é UUID e por que ele foi criado?
UUID (Universally Unique Identifier) é um identificador de 128 bits, geralmente representado por uma string hexadecimal como:
550e8400-e29b-41d4-a716-446655440000
Os tipos mais comuns de UUID são:
- UUID v1: Baseado em timestamp e MAC address do dispositivo
- UUID v4: Totalmente aleatório
- UUID v5: Baseado em hash (SHA-1) de um namespace e um valor.
A ideia por trás da criação dos UUIDs surgiu como solução para um problema comumente enfrentado em bancos de dados distribuídos e sistemas multiusuário. Antigamente, quando banco de dados passaram a ser acessados em rede, um dos desafios era garantir que vários clientes pudessem gerar identificadores únicos sem entrar em conflito. Antes disso, os sistemas baseados em auto-incremento enfrentavam problemas de concorrência, onde transações simultâneas podiam gerar colisões.
Com o tempo, soluções como sequentes (PostgreSQL, Oracle) e funções de recuperação do último inserido (como SCOPE_IDENTUTY() no SQL Server) ajudaram a minimizar esse problema. No entanto, para sistemas totalmente distribuídos, onde várias instâncias de banco de dados precisam gerar identificadores sem sincronização, UUIDs passaram a ser adotados.
GUID da Microsoft
GUID (Globally Unique Identifier) é essencialmente o mesmo conceito de UUID, mas é um termo.mais comumente utilizado no ecossistema da Microsoft. Ele é gerado por funções como NEWID() no SQL Server e é amplamente utilizado em sistemas Windows. Embora tenha as mesmas vantagens de unicidade global, também sofre dos mesmos problemas de desempenho quando usado como chave primária em bancos relacionais. A promessa do UUID/GUID é que ele permite gerar identificadores globalmente únicos, sem necessidade de consulta ao banco de dados para evitar colisões. Mas isso significa que ele é mais seguro?
UUID protege contra SQL Injection? NÃO!
Um dos argumentos mais comuns para justificar UUID como mais seguro é que um atacante não saberia qual ID existe na base de dados e, portanto, não poderia tentar acessar registros de forma previsível.
Isso é um erro!
Se um sistema é vulnerável a SQL Injection, tanto faz se a chave é um UUID ou um ID sequencial. Veja um exemplo:
SELECT * FROM usuarios WHERE id = '550e8400-e29b-41d4-a716-446655440000' OR '1'='1'
Se a query não for parametrizada, o ataque funcionaria da mesma forma. O problema não está no formato do identificador, mas sim na falta de segurança na execução das queries.
A solução correta para se evitar SQL Injection:
- Usar queries parametrizadas
Query.SQL.Text := 'SELECT * FROM usuarios WHERE id = :id';
Query.ParamByName('id').AsString := '550e8400-e29b-41d4-a716-446655440000';
Query.Open;
- Sanitizar entradas do usuário
- Evitar a construção dinâmica de queries sem validação
O grande problema dos UUIDs: Indexação
Usar UUIDs como chave primária pode gerar uma degradação de desempenho significativa em banco de dados relacionais. O motivo é simples:
A Chave Primária é usada como base para outros índices. Se o ID for aleatório, os registros serão espalhados na estrutura de armazenamento, causando fragmentação e baixa performance.
Em bancos que usam B-Trees para indexação (como PostgreSQL, MySQL e SQL Server), UUIDs aleatórios quebram a eficiência dos índices.
- IDs sequenciais permitem inserção ordenada, mantendo o índice balanceado.
- UUIDs são distribuídos aleatoriamente, forçando o banco a reequilibrar índices o tempo todo.