Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Certificado Público

Boa noite! No curso não vi exemplo que como seria a decodificação de um token JWT usando um certificado público .. Seria possível gerar o certificado público no Nodes? Pergunto isso para evitar estar usando a chave privada para decodificar o token... mesmo ela estando criptografada, vi em alguns post que não seria uma boa prática... o mas aconselhavel seria disponibilizar o certificado público que seria usado pelos serviços que iria fazer a validação do token.

1 resposta
solução!

Oi, Daniela!

Realmente, nesse curso não foi mostrado como usar JWT com algoritmos assimétricos de assinatura. Então, nós temos apenas um segredo (a chaveJWT) e não dois tipos de chaves (chave pública e chave privada). Ambos os métodos são válidos e isso depende do tipo da sua aplicação.

No caso do curso, o servidor que gera os tokens é o mesmo que verifica eles, por isso podemos usar um algoritmo simétrico de assinatura (por exemplo, HMAC + SHA256), que usa apenas uma chave secreta, para assinar o token. Além disso, esse é um método mais fácil de implementar e é muito mais rápido que outros métodos.

Entretanto, se você estiver numa situação na qual um servidor que gera os tokens e um ou mais servidores diferentes que verificam os tokens, então é necessário utilizar um algoritmo assimétrico para assinatura. Os mais comuns são o RS256 (assinatura do RSA + SHA256) e ES256 (assinatura do ECDSA + SHA256). Como escolher eles? Basicamente, o RSA é mais rápido mas o ECDSA permite chaves menores, então é uma escolha que depende do seu caso. De qualquer forma, ambos os métodos são bem mais lentos e complexos que o HMAC.

Vamos ver então um exemplo de JWT com o algoritmo RS256. Primeiro, é preciso gerar as chaves pública e privada. Para isso, podemos criar um programa generate-keys.js como o abaixo:


const fs = require('fs');
const { generateKeyPair } = require('crypto');

// substituir 'senha super secreta' por uma senha aleatória 
// e guardada em variável de ambiente
const senha = 'senha super secreta';

generateKeyPair('rsa', {
  modulusLength: 4096,
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
    cipher: 'aes-256-cbc',
    passphrase: senha
  }
}, (erro, chavePublica, chavePrivada) => {
    fs.writeFileSync('public.pem', chavePublica);
    fs.writeFileSync('private.key', chavePrivada);
    }
);

Com isso, ao rodar o programa com node generate-keys.js no seu servidor de autenticação, você vai gerar dois arquivos:

  • public.pem, com a chave pública;
  • private.key, com a chave privada criptografada.

Assim, para gerar os tokens, seu servidor de autenticação deverá fazer algo da forma

// [...]
const fs = require('fs');
const jwt = require('jsonwebtoken');

// o arquivo 'private.key' pode não estar no mesmo diretório que o programa
const privateKey = fs.readFileSync('private.key');

// substituir 'senha super secreta' pela senha usada na geração
// das chaves e guardada em variáveis de ambiente
const senha = 'senha super secreta';

const token = jwt.sign(
    payload,
    { key: privateKey, passphrase: senha},
    { algorithm: 'RS256', expiresIn: tempoExpiracao }
);

// [...]

e, para verificar o token, os outros servidores podem executar

// [...]
const fs = require('fs');
const jwt = require('jsonwebtoken');

// o modo como o serviço adquire a chave pública pode
// variar de acordo com a implementação
const publicKey = fs.readFileSync('public.pem');

const payload = jwt.verify(token, publicKey);
// [...]

É importante notar que essa é uma implementação mais complexa, principalmente pela administração adicional das chaves que é preciso ser feita. Por isso, recomendo ler esse artigo da Ping identity(em inglês) que explica as considerações adicionais de segurança que você precisará ter.

Mesmo assim, esse é o panorama geral de como usar JWT com algoritmos assimétricos de assinatura.

Se tiver mais alguma dúvida, é só falar ;)

Abraços!