Introdução aos JSON Web Tokens (JWT)
Os JSON Web Tokens, comumente conhecidos pela sigla JWT, representam um padrão aberto baseado em JSON. Sua principal finalidade é facilitar a troca segura e compacta de informações entre duas partes, sendo frequentemente empregados em processos de autenticação e autorização.
Estrutura de um JWT
Um JWT é composto por três partes distintas, separadas por pontos (.), formando uma sequência compacta e segura para URL. Estas partes são o Cabeçalho (Header), o Payload e a Assinatura (Signature), seguindo o formato:
Header.Payload.Signature
Um exemplo prático de um JWT pode ser:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Vamos analisar cada um dos componentes que formam este token.
1. Cabeçalho (Header)
O cabeçalho é um objeto JSON que tipicamente especifica o tipo do token (typ) e o algoritmo de criptografia (alg) utilizado para assinar o JWT. No exemplo acima, o token é do tipo JWT e usa o algoritmo HMAC-SHA256.
O conteúdo JSON do cabeçalho seria:
{
"alg": "HS256",
"typ": "JWT"
}
Este objeto JSON é então codificado usando o algoritmo Base64Url. A codificação Base64Url é uma variante da Base64 padrão, otimizada para uso em URLs, substituindo caracteres específicos ('+' por '-' e '/' por '_') e omitindo o preenchimento com '='. A parte codificada do cabeçalho corresponde à primeira seção do JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2. Payload (Carga Útil)
O payload é o corpo principal do JWT e contém as "declarações" (claims) sobre uma entidade (geralmente o usuário) e metadados adicionais. As claims são informações que podem ser utilizadas pelo servidor ou cliente. Existem três tipos de claims:
Declarações Registradas (Registered Claims)
São um conjunto de claims predefinidas, recomendadas, mas não obrigatórias. Elas fornecem um conjunto de atributos interoperáveis:
iss: Emissor do JWT.sub: Assunto do JWT (entidade que o token representa).aud: Audiência do JWT (para quem o token se destina).exp: Tempo de expiração do JWT (em timestamp UNIX).nbf: "Not Before" — indica a partir de qual tempo o JWT será aceito (em timestamp UNIX).iat: "Issued At" — indica o tempo em que o JWT foi emitido (em timestamp UNIX).jti: ID único do JWT, para evitar ataques de replay.
Declarações Públicas (Public Claims)
Podem ser definidas livremente por aqueles que utilizam JWTs. É crucial que sejam registradas no IANA JSON Web Token Registry ou que recebam um URI para evitar colisões. É recomendado que não contenham informações sensíveis, pois não são criptografadas, apenas codificadas.
Declarações Privadas (Private Claims)
São declarações personalizadas criadas entre as partes que estão concordando em usar o JWT, como cliente e servidor. Da mesma forma que as públicas, não devem conter dados sensíveis sem criptografia adicional.
O conteúdo JSON do payload do nosso exemplo seria:
{
"sub": "1234567890",
"name": "João Ninguém",
"iat": 1516239022
}
Após a codificação Base64Url, o payload forma a segunda parte do token:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
3. Assinatura (Signature)
A assinatura é criada combinando o cabeçalho codificado em Base64Url, o payload codificado em Base64Url, um segredo (secret) e o algoritmo especificado no cabeçalho. Sua função é verificar a integridade do token, garantindo que não foi alterado por terceiros. Ela também confirma que o emissor é quem diz ser.
A assinatura é calculada da seguinte forma:
ASSINATURA = ALGORITMO_DE_HASH(
BASE64URL_CODIFICADO(CABECALHO) + "." + BASE64URL_CODIFICADO(PAYLOAD),
SEGREDO_SEGURO
)
Para o exemplo dado, usando HMACSHA256 com um segredo específico, a assinatura resultante é:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Vantagens do JWT
- Ausência de Estado e Escalabilidade: Servidores não precisam armazenar informações de sessão, tornando a aplicação mais escalável e stateless.
- Prevenção de Ataques CSRF: Por serem geralmente transmitidos via cabeçalho
Authorization: Bearere não via cookies, JWTs ajudam a mitigar ataques de Cross-Site Request Forgery (CSRF). - Eficiência na Transmissão de Dados: O payload pode conter dados essenciais e não sensíveis, reduzindo a necessidade de consultas adicionais ao banco de dados para obter informações básicas do usuário.
- Interoperabilidade: Sendo um padrão aberto baseado em JSON e usando algoritmos de criptografia comuns, JWTs são amplamente suportados em diversas linguagens e plataformas.
- Leveza e Propósito Definido: Diferente de frameworks de autorização como OAuth2 (que gerencia permissões para aplicações de terceiros), JWT é uma solução de autenticação compacta para cenários como APIs RESTful.
Desvantagens do JWT
- Imutabilidade: Uma vez emitido, um JWT não pode ser alterado. Para atualizar dados ou estender a validade, um novo token deve ser gerado e enviado ao cliente.
- Dificuldade de Revogação Imediata: JWTs são válidos até a sua expiração. Revogar um token antes do tempo (por exemplo, após um logout ou alteração de senha) exige mecanismos adicionais no lado do servidor, como listas negras (blacklists).
- Exposição de Dados no Payload: O payload é codificado (Base64Url), não criptografado. Informações sensíveis nunca devem ser armazenadas diretamente no payload sem criptografia adicional.
- Risco de Vazamento: Se um JWT é interceptado ou exposto, ele concede acesso completo à entidade que ele representa durante seu período de validade. Por isso, a duração dos tokens deve ser cuidadosamente gerenciada.
- Vulnerabilidade
alg=none: Alguns frameworks podem, se não configurados corretamente, aceitar tokens com o algoritmononeno cabeçalho, permitindo que um atacante falsifique um token sem uma assinatura válida. É crucial desabilitar explicitamente esta opção. - Ataques de Força Bruta ao Segredo (HMAC): Se o segredo usado para assinar o token HMAC for fraco, e um atacante tiver acesso a tokens válidos, ele pode tentar ataques de força bruta offline para descobrir o segredo.