Artigo
JSON Web Signature (JWS) – RFC 7515JSON Web Signature (JWS) – RFC 7515
Fabrício de Medeiros
JSON Web Signature (JWS) – RFC 7515
O JWS - JSON Web Signature é um padrão aberto definido pela RFC 7515 (maio de 2015) que estabelece um formato JSON para assinar dados digitais. Ele assegura a integridade de informações usando assinaturas digitais ou MAC - Message Authentication Codes sobre o conteúdo (payload) codificado em JSON.
Em outras palavras, um JWS é um objeto que contém:
(1) um cabeçalho (JOSE Header);
(2) um payload (mensagem arbitrária);
(3) uma assinatura (ou código de autenticação de mensagem).
Esses elementos fornecem proteção criptográfica ao conteúdo, tornando impossível alterá-lo sem invalidar a assinatura.
A RFC 7515 define dois formatos de serialização do JWS:
Compact (cadeia de caracteres curta, própria para cabeçalhos HTTP e URLs)
JSON (objeto JSON que pode conter múltiplas assinaturas).
Esses formatos usam Base64url (codificação Base64 sem padding) para representar os componentes binários de forma segura em texto.
Segundo a definição oficial, “JWS representa conteúdo protegido com assinaturas digitais ou MACs usando estruturas de dados baseadas em JSON”. Em linguagem simples, o JWS protege dados contra adulteração, garantindo que o receptor possa detectar qualquer modificação. Por exemplo, a Wikipedia resume que o JWS é um padrão proposto pelo IETF para “assinar dados arbitrários”, servindo de base para tokens como o JWT. Como a RFC lembra, cabe às implementações compreenderem parâmetros obrigatórios e rejeitar ou ignorar os não entendidos. No contexto de APIs modernas, JWS é amplamente usado para criar tokens de autenticação (por exemplo, JWTs) que levam reivindicações (claims) sobre o usuário, data de expiração, etc., protegidas por assinatura para evitar fraudes.
ESTRUTURA DE UM JWS
Um JWS consiste em três componentes principais:
· Protected Header (cabeçalho protegido) – objeto JSON contendo parâmetros de assinatura (por exemplo, algoritmo, tipo de token, ID de chave). Este cabeçalho é incluído na assinatura, garantindo sua integridade. No Compact Serialization, todo o cabeçalho é protegido.
· Payload (corpo) – os dados a serem protegidos; pode ser qualquer sequência de octetos (tipicamente JSON com claims). A RFC enfatiza que o payload “pode conter uma sequência arbitrária de octetos”, ou seja, não há restrição de formato.
· Signature (assinatura) – o valor do MAC ou assinatura digital aplicado ao cabeçalho protegido concatenado com o payload. Mais formalmente, a assinatura é calculada sobre o Signing Input, que é a concatenação ASCII de BASE64URL(JWS Protected Header) || '.' || BASE64URL(JWS Payload). O resultado é então codificado em Base64url.
Em resumo:
· Entrada de Assinatura (Signing Input) = Base64url(UTF8(cabeçalho)) + "." + Base64url(payload).
· Assinatura Final = Base64url(algoritmo(Signing Input)).
Na versão compacta do JWS, os três campos são unidos por pontos, gerando uma string com três partes:
BASE64URL(UTF8(Header)) . BASE64URL(Payload) . BASE64URL(Signature).
Por exemplo, a RFC ilustra um JWS compacto (algoritmo HMAC-SHA256) onde cada parte é codificada em Base64url e concatenada com pontos. O receptor pode então reconstruir o Signing Input a partir do cabeçalho e payload recebidos, recalcular o valor do algoritmo (com a chave adequada) e compará-lo com a assinatura recebida.
A RFC define ainda o JOSE Header, que unifica os parâmetros de cabeçalho protegidos e não protegidos. No Compact Serialization, não há cabeçalho não protegido; já na JSON Serialization, é possível ter múltiplas assinaturas e até campos de cabeçalho sem proteção adicional. Para tokens em APIs (caso mais comum), costuma-se usar o modo compacto, pois é mais enxuto e fácil de transportar em cabeçalhos HTTP ou URLs.
Parâmetros do Cabeçalho (JOSE Header)
O cabeçalho de um JWS é um objeto JSON que indica como a assinatura foi gerada. Os parâmetros registrados mais relevantes incluem:
· alg (algorithm) – Obrigatório. Identifica o algoritmo criptográfico usado (por exemplo, HS256, RS256, ES256, etc.). Se este valor não corresponder a um algoritmo suportado ou se não houver chave correspondente, a assinatura é inválida. A RFC estabelece que o campo “alg” MUST estar presente e ser compreendido pela implementação. Seus valores padrão são definidos no registro IANA de JWA (JSON Web Algorithms) e incluem HMAC+SHA (HS256, HS384, HS512), RSA+SHA (RS256, RS384, RS512), ECDSA (ES256, ES384, ES512) e outros. É prática recomendada validar explicitamente o algoritmo esperado e não confiar em valores arbitrários (evitando ataques de substituição de algoritmo).
· typ (type) – Tipo do token. Geralmente opcional, mas usado para indicar que o conteúdo é um JWT. Por exemplo, o header pode conter "typ":"JWT" para sinalizar JSON Web Token.
· kid (Key ID) – Opcional. Identificador da chave que assinou o token, utilizado para seleção de chave no servidor ou cliente. É um hint para informar qual chave pública deve ser usada para verificar a assinatura. O valor de kid é normalmente uma string curta definida pela aplicação.
· Outros parâmetros – Como cty (content type, por exemplo para payloads aninhados) ou campos de certificado X.509 (x5c, x5u), que a RFC documenta, mas são menos comuns em tokens de uso geral. Implementações devem ignorar parâmetros desconhecidos (exceto quando marcados como críticos) para manter a compatibilidade.
Por exemplo, na RFC 7515 o header JSON de um JWS de exemplo é {"typ":"JWT","alg":"HS256"}, indicando que se trata de um token JWT assinado com HMAC-SHA256. Em implementações reais, esses campos são codificados em Base64url como parte do Signing Input.
Serialização Compacta e JSON
A RFC 7515 define duas maneiras de representar um JWS:
· Compact Serialization – Uma string de três partes (header, payload, assinatura) separadas por pontos. Cada parte é Base64url codificada (sem padding)datatracker.ietf.org. Exemplo genérico de formato:
<Base64url(Header)>.<Base64url(Payload)>.<Base64url(Signature)>
Essa forma é ideal para tokens curtos (como JWT) e envio por cabeçalhos HTTP (Authorization: Bearer <token>). A base64url emprega o alfabeto URL-safe do RFC 4648, omitindo “=” finais.
· JSON Serialization – Um objeto JSON contendo alguns campos: "protected" (header protegido em Base64url), "payload" (payload em Base64url), "signature" (assinatura em Base64url), e opcionalmente "header" (header não-protegido), ou até um array "signatures" para múltiplas assinaturas. Por exemplo, um JWS JSON pode ser:
{
"payload": "<Base64url do payload>",
"protected": "<Base64url do cabeçalho>",
"signature": "<Base64url da assinatura>"
}
· Essa forma permite múltiplas assinaturas/MACs no mesmo objeto, mas é menos compacta e não é usada em Authorization headers. É raramente necessária em APIs simples, sendo mais comum em situações avançadas (ex.: vários signatários).
Em ambas as serializações, o significado semântico é o mesmo: um token assinado. Na prática de APIs, usamos quase sempre o compacto por ser simples e eficiente, conforme ilustrado nos exemplos a seguir.
Uso de JWS como Token em APIs
Em APIs modernas, JWS é usado principalmente para criar tokens de acesso/autenticação (por exemplo, o padrão JSON Web Token – JWT, definido na RFC 7519). Um JWT não é mais do que um JWS cujo payload contém um conjunto de claims (reivindicações) padrão, como emissor (iss), sujeito (sub), audiência (aud), timestamps (exp, iat), etc. O JWS garante que esses dados não foram alterados: uma modificação em qualquer claim (como estender a data de expiração) invalidaria a assinatura.
Por exemplo, considere uma API que emite um token JWT assinado. O servidor define um payload JSON com algo como {"iss":"api.exemplo.com","exp":1630000000,"user_id":42}, e um header {"alg":"HS256","typ":"JWT"}. A chave secreta (ou par de chaves) do servidor é usada para produzir a assinatura. O token resultante é uma string compacta do tipo:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<payload codificado>. <assinatura codificada>
(onde cada trecho acima é codificado em Base64url). Essa estrutura transmite ao cliente web ou aplicativo mobile não somente as informações do usuário, mas também a garantia de integridade. Se o token for apresentado de volta ao servidor em chamadas futuras (por exemplo, no header Authorization: Bearer <token>), o servidor pode decodificá-lo, verificar a assinatura usando a chave secreta/privada, e então confiar nos claims contidos, como o ID do usuário e a expiração.
É importante salientar que, conforme definido no RFC, a especificação JWS não impõe quais claims incluir – isso fica a cargo da aplicação (por exemplo, no caso de JWT). Tipicamente, as APIs incluem pelo menos exp para limitar a validade, iss para indicar quem emitiu o token, e sub ou user_id para referenciar o usuário final. Estes campos são parte do payload, que é protegido pela assinatura. Assim, qualquer tentativa de alterar a payload (por exemplo, aumentando exp ou mudando user_id) será detectada quando o servidor recalcular a assinatura.
Exemplos de Implementação em PHP
Para implementar JWS/JWT em PHP, há bibliotecas maduras que já seguem as RFCs do JOSE. Um exemplo popular é a firebase/php-jwt, que codifica/decodifica JWT conforme a RFC 7519 (baseada em JWS). A seguir um exemplo de criação e validação de um token JWS (compacto) usando esta biblioteca.
<?php
require 'vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// Chave secreta compartilhada (para HS256)
$key = 'minha_chave_secreta';
// 1. Definir o payload com claims desejados
$payload = [
'iss' => 'https://api.exemplo.com', // Emissor do token
'exp' => time() + 3600, // Expiração (agora + 1 hora)
'sub' => 123, // ID do usuário (exemplo)
// ... outros claims customizados ...
];
// 2. Gerar o JWS (compacto) assinado usando HS256
$jwt = JWT::encode($payload, $key, 'HS256');
echo "Token JWS gerado: " . $jwt . "\n";
Nesse exemplo, usamos JWT::encode() passando o payload, a chave secreta e o algoritmo HS256 (HMAC-SHA256). Conforme o próprio repositório instrui, é importante especificar explicitamente os algoritmos suportados pela aplicação. A variável $jwt terá então uma string no formato header.payload.signature.
Para verificar o token recebido em chamadas subsequentes, fazemos:
<?php
// Suponha que $jwt recebeu o token JWS enviado pelo cliente
try {
// Decodifica e verifica a assinatura. Lança exceção se inválido.
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
// $decoded é um objeto com os claims do payload
$claims = (array) $decoded;
echo "Token válido. Claims:\n";
print_r($claims);
} catch (Exception $e) {
// Se ocorrer qualquer erro (assinatura inválida, token expirado, etc.)
echo "Token inválido: " . $e->getMessage();
}
Aqui, JWT::decode() faz o processo inverso: decodifica o JWS e valida a assinatura usando a mesma chave e algoritmo (HS256). Se a assinatura não bater, ou se o token tiver expirado (campo exp ultrapassado), a biblioteca gera uma exceção. Caso contrário, retornará o conteúdo do payload (o objeto $decoded) contendo as reivindicações originais. Em versões mais recentes da biblioteca é necessário passar um objeto Key indicando a chave e o algoritmo (como acima). O resultado $decoded pode ser convertido para array ((array) $decoded) para fácil acesso.
Observação: No GitHub do php-jwt consta um exemplo similar github.com, reforçando que é preciso definir e verificar o algoritmo esperado. Além disso, sempre valide outras condições (como iss, aud, exp) segundo a lógica da sua API para evitar abusos. Em bibliotecas alternativas (por exemplo para RSA/ECDSA) haveria um passo extra de obtenção da chave pública (JWK ou PEM) para verificar a assinatura, mas o fluxo geral é análogo.
Boas Práticas e Segurança
· Especifique algoritmos suportados: Nunca aceite qualquer valor de "alg" sem validação. Por exemplo, ataques conhecidos usam "alg":"none" se a aplicação não impedir, ou substituição de algoritmo. A biblioteca mencionada já alerta para isso.
· Verifique todos os campos críticos: Além de exp (expiração), cheque o iss (emitente) e aud (destinatário) conforme sua aplicação. Tokens expirados ou de fontes inesperadas devem ser rejeitados.
· Proteja a chave: No caso de HMAC (como HS256), a chave secreta deve ser mantida segura no servidor e suficientemente randômica. Para algoritmos assimétricos (RS256, ES256), use pares RSA/ECDSA fortes; o servidor mantém a chave privada secreta e fornece a pública (JWK) aos validadores. Use o cabeçalho kid para rotação de chaves, apontando qual JWK usar.
· Use TLS/HTTPS: Sempre transmita tokens sobre canais seguros (TLS) para evitar interceptação. A RFC também menciona que recursos referenciados por jku ou x5u devem ser acessados via TLS confiável.
· Base64url sem padding: Os componentes devem usar base64url sem “=” finais. Isso é crucial na montagem do token; bibliotecas de referência já fazem isso corretamente.
· JSON seguro: As implementações devem fazer parsing JSON rigoroso e prevenir malformações. Por exemplo, não use funções inseguras para interpretar o header/payload sem validação, pois isso pode levar a problemas de segurança.
Em resumo, um JWS bem implementado fornece autenticação de mensagem robusta: o receptor confia que os dados vêm do emissor legítimo e não foram adulterados. A RFC 7515 detalha vários aspectos técnicos, mas a essência para desenvolvedores de API é: crie seu token definindo cabeçalho (alg, possivelmente typ="JWT"), payload com suas reivindicações e assine com sua chave. Na validação, decodifique e confira a assinatura e a validade do conteúdo. Seguindo a especificação e as práticas acima, você terá um mecanismo de tokens de alta confiança, condensado em convenientes strings "header.payload.signature".
Explore, Contribua e Cresça Conosco!
Obrigado por ler o nosso artigo! Esperamos que você tenha encontrado informações valiosas e inspiradoras. Se você está empolgado para saber mais, temos uma vasta coleção de artigos sobre tópicos variados, desde tendências tecnológicas até insights sobre desenvolvimento de software. Não deixe de explorar nossas outras publicações!
Quer fazer parte da nossa comunidade?
Inscreva-se no nosso site para receber as últimas atualizações e novidades diretamente no seu e-mail. Seu cadastro é o primeiro passo para se conectar com uma rede de entusiastas e profissionais apaixonados pelo que fazem.
Tem algo a compartilhar?
Adoraríamos ouvir suas ideias, inovações e experiências! Sinta-se à vontade para escrever e enviar seus próprios artigos, códigos ou projetos. Sua contribuição é fundamental para enriquecer nosso conteúdo e ajudar outros leitores a crescer junto com você. Juntos, podemos criar um espaço de aprendizado e troca de conhecimento enriquecedor. Seu conhecimento e entusiasmo são o que fazem nossa comunidade especial.
Inscreva-se Agora | Compartilhe | Contribua com um Artigo
Continue explorando e seja parte da transformação!