paint-brush
AJUDA! Há um JWT no meu Metaverso!por@patrickleet
1,709 leituras
1,709 leituras

AJUDA! Há um JWT no meu Metaverso!

por Patrick Lee Scott8m2022/07/25
Read on Terminal Reader
Read this story w/o Javascript

Muito longo; Para ler

O advento da Web3 e o uso generalizado de carteiras levarão os usuários a abandonar os sistemas de contas tradicionais baseados em e-mail/senha e, em vez disso, fazer login usando suas carteiras. Os JWTs, embora um pouco confusos no início, são incrivelmente úteis para engenheiros de back-end, especialmente aqueles de sistemas de microsserviços. A multidão “parafuso-JWT” sugere o uso de IDs de sessão simples, mas este é um retrocesso para o início dos anos 2000, quando arquiteturas simples em camadas eram o padrão, que não tinham as complexidades dos sistemas de back-end de hoje. Patrick Lee Scott explora o uso de JWTs em um mundo web3.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - AJUDA! Há um JWT no meu Metaverso!
Patrick Lee Scott HackerNoon profile picture

Os JWTs estão realmente mortos ou são apenas mal compreendidos?

Tenho visto alguns artigos recentemente sugerindo que o advento da Web3 e o uso generalizado de carteiras levarão os usuários a abandonar os sistemas de contas tradicionais baseados em e-mail/senha e, em vez disso, fazer login usando suas carteiras.


Para ser honesto, depois de usar alguns dApps, o fluxo de trabalho super simples de um ou dois cliques em sua carteira é realmente uma experiência superior.


Muitos desses artigos dizem “oba, não precisamos mais de JWTs!”.


É aqui que discordo.


Os JWTs, embora um pouco confusos no início, são incrivelmente úteis para engenheiros de back-end, especialmente aqueles de sistemas de microsserviços. Principalmente , considerando que esses sistemas - um grande número deles - já existem e já se integram com JWTs! Ethereum é ótimo e tudo, mas realmente não precisamos reinventar a roda. É bom poder continuar usando as mesmas ferramentas de back-end com as quais você está acostumado quando precisar.


Fazer login com MetaMask prova que é você - mas como você prova para futuras chamadas de API que é você?


A multidão “parafuso-JWT” sugere o uso de IDs de sessão simples, mas isso é um retrocesso para o início dos anos 2000, lembre-se, quando arquiteturas simples em camadas eram o padrão, que não tinham as complexidades dos sistemas de back-end de hoje.


Infelizmente, os IDs de sessão não podem ser verificados sem uma ida e volta adicional ao banco de dados para determinar se o ID de sessão concedido pertence ou não a uma sessão válida. Isso significa que, quando o serviço de back-end recebe a solicitação que contém o ID da sessão, ele faz uma solicitação ao servidor de autenticação perguntando "está ativo" - e todos os outros serviços no sistema Microservice perguntam o mesmo.


Se houver vários serviços envolvidos, isso pode significar várias idas e vindas adicionais ao serviço de autenticação.


Para remediar esta situação, os especialistas em criptografia começaram a pensar.


O que eles criaram foram JWTs - agora parte do padrão OpenID, você sabe, aquele que Keycloak, Auth0 e outros ajudam você a implementar.

JWTs, pessoal

A solução foi conceder um conjunto de tokens - JSON Web Tokens para ser mais preciso. Esse conjunto consiste em um AccessToken , um RefreshToken e um IdToken . Esses tokens foram então “assinados” por um segredo - geralmente chamado de ClientSecret . A assinatura, só para estarmos na mesma página, é um algoritmo de hash criptográfico, no caso de JWTs – geralmente HS256 (o padrão para Auth0). No caso do HS256 o ClientSecret é usado como entrada e, portanto, torna-se a chave necessária para decifrar com sucesso esse hash - ou "verificá-lo". Com RS256 e ES256 um par de chaves pública/privada é usado, ou seja, assinado por chave privada e verificado com chave pública no cliente.


Isso significa que, se um serviço de back-end receber um desses tokens e conhecer o ClientSecret , ele poderá verificar se o token foi realmente emitido pelo serviço de autenticação que assinou esse token. O token usado ao tentar acessar um serviço de back-end é o AccessToken . Esses tokens contêm especificamente informações sobre quem é o usuário, bem como suas “reivindicações”, ou seja, o que eles podem fazer formatado para o sistema que se preocupa com isso.


Para sistemas de microsserviço, isso significa que cada serviço que se preocupa em verificar a identidade só precisa saber sobre o ClientSecret , pois eles podem verificar se o JWT é autêntico usando-o, em vez de uma viagem de ida e volta ao banco de dados. Em um sistema com muitos microsserviços, isso pode reduzir muitas idas e vindas adicionais ao banco de dados, tornando todo o sistema mais escalável.


Os tokens de acesso, se roubados, podem ser usados de forma maliciosa e, por isso, é importante tomar as devidas precauções ao projetar um sistema para usá-los.


O conjunto mínimo de precauções, além de assinar e verificar os tokens, consiste em:


  1. Definir uma data de expiração no Access Token JWT de 5 a 15 minutos e garantir que os tokens não expirem quando recebidos

  2. Não armazene o token de acesso, exceto na memória

  3. Emitir tokens de atualização que podem ser armazenados e enviados a um servidor para verificação e atualizados junto com o uso de ClientSecret e ClientId que o emitiram.

  4. Use somente quando transmitido por conexões TLS (HTTPS)

  5. Use cookies HTTP Only para que eles não possam ser modificados no lado do navegador

  6. Configurações do CORS

  7. Uma chave do mesmo tamanho da saída hash (por exemplo, 256 bits para "HS256") ou maior DEVE ser usada com este algoritmo. - RFC7518 , nota: Auth0 usa 512 bits para HS256.


Um cliente confidencial precisa de um servidor intermediário, como o Node.js - esse servidor é um proxy para o serviço de autenticação, portanto, o cliente não precisa saber sobre o segredo do cliente. Um cliente público expõe o segredo do cliente e não há um servidor proxy entre o navegador e o serviço de autenticação. Isso pode ser restringido ainda mais com as configurações do CORS, de modo que apenas solicitações de determinados domínios sejam permitidas.


Precauções adicionais incluem:


  1. Use tokens de atualização rotativa - cada um só pode ser usado uma vez. Quando usado, ele é trocado por um novo conjunto de tokens e o token de atualização trocado é revogado. Se essa estratégia for empregada, vale a pena notar que os usuários com uma conexão de internet ruim às vezes podem não receber a resposta à solicitação de atualização e tentar novamente. Por esse motivo, um curto período de carência de 30 segundos ou mais permitirá que eles atualizem e tentem novamente.
  2. Permitir que o usuário revogue todos os seus tokens de atualização existentes ao fazer logout.


E provavelmente mais - por exemplo, se você detectar alguém tentando usar um token de atualização revogado, poderá revogar todos os tokens de atualização ativos desse usuário.


Todas essas precauções, reconhecidamente, podem tornar um pouco difícil acertar. Há muito o que entender. Também há preocupações de usabilidade. Um usuário que se deslogou do seu site a cada 5 minutos seria muito irritante para ele. Para evitar isso, um loop de atualização silenciosa deve ser implementado no aplicativo de consumo para atualizar continuamente o conjunto de tokens.


Dito isso, do outro lado de acertar, é ser capaz de integrar com segurança todos os seus sistemas de back-end de maneira escalável, bem como muitas ferramentas existentes - como Hasura , que pode gerar automaticamente todas as suas APIs para você com base em um esquema de banco de dados do Postgres conectado. Assim, ser capaz de integrar-se facilmente com ferramentas existentes pode economizar muito tempo de desenvolvimento.


Se você já usa o OpenId, é provável que já tenha essas coisas em vigor. Afinal, é um padrão de autenticação.


Então, como podemos manter a conveniência de usar JWTs em um Web3 e fazer login com o mundo MetaMask?

JWTs e Web3?

Vamos começar entendendo o fluxo de autenticação OpenId usado para SSO.


  1. Você visita um site e deseja fazer login com sua conta - você clica no botão de login
  2. Você é redirecionado para a página de login do SSO - faça o login com um e-mail/nome de usuário e senha
  3. Você é redirecionado de volta ao aplicativo original com um conjunto de JWTs que são armazenados adequadamente e usados em fluxos de plano de fundo de atualização silenciosa.


No mundo web3auth, estamos substituindo a etapa dois pelo uso dos pares de chaves pública e privada de sua carteira para assinar um desafio. O redirecionamento não é necessário ou desejado.


  1. Você visita um site e deseja fazer login com sua conta - você clica no botão de login

  2. Você recebe um desafio do servidor de autenticação que abre sua carteira pedindo para você “assinar” o desafio. Pressione o sinal.

  3. O servidor de autenticação verifica sua assinatura e emite um conjunto de JWTs que são armazenados adequadamente e usados em fluxos de segundo plano de atualização silenciosa.



Estamos simplesmente substituindo o fluxo de redirecionamento do estilo SSO por um desafio assinado por sua carteira. O fluxo após o recebimento dos tokens permanece o mesmo do OpenID. Isso significa que você poderia, por exemplo, mudar de usar OpenID para usar web3auth com um servidor emissor de JWT, e nada sobre o uso desses tokens depois que eles forem concedidos precisaria mudar. Todas as suas integrações de back-end existentes com ferramentas como Hasura permanecem exatamente as mesmas.


Isso é exatamente o que eu quero como desenvolvedor Full Cycle. Não quero reinventar a roda. Quero substituir o OpenID pelo web3auth e ainda poder usar todas as ferramentas poderosas com as quais estou acostumado.


Infelizmente, não consegui encontrar um servidor web3auth que fizesse isso, além das precauções de segurança. Encontrei alguns projetos demonstrando técnicas no processo, mas não todo o fluxo de ponta a ponta.


Então eu comecei a construir…


Eu construí este servidor de autenticação aqui: https://github.com/CloudNativeEntrepreneur/web3auth-service


E aqui está a integração do SvelteKit para acompanhar, que implementa todas as coisas - atualização silenciosa, yada yada - todas as coisas que mencionei acima: https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth


É claro que, se haveria um cliente GraphQL e um exemplo, também seria necessário um servidor e banco de dados GraphQL, então também forneci exemplos disso: https://github.com/CloudNativeEntrepreneur/example-hasura + https: //github.com/CloudNativeEntrepreneur/example-readmodel


Este exemplo usa o operador Zalando Postgres e SchemaHero , portanto, tudo o que você precisa fazer é declarar seus bancos de dados e descrever seu esquema em YAML, e o Hasura gerará automaticamente todas as APIs GraphQL necessárias. E, eu criei o servidor de autenticação com Hasura em mente, para que ele tenha as declarações adequadas para se integrar ao RBAC e às permissões de Hasura, que são bastante robustas.


E, claro, você precisa de um local para executar tudo isso e, portanto, um cluster de desenvolvimento local que configure todas as ferramentas, como istio, operadores e SchemaHero para você! https://github.com/CloudNativeEntrepreneur/local-dev-cluster


Mas quem sabe usar tudo isso?


É por isso que fiz este meta repo: https://github.com/CloudNativeEntrepreneur/web3auth-meta


O uso desse meta repo clonará todos os projetos de que você precisa nos lugares certos e os executará todos juntos.


Por fim, para rodar todos os projetos juntos, você precisa de ferramentas instaladas, e instalar ferramentas é chato - então fiz esse repo aqui que vai instalar todas elas para você! https://github.com/CloudNativeEntrepreneur/onboard


Também publiquei sveltekit-web3auth no npm e criei um modelo de um projeto SvelteKit que o usa e tem o GraphQL configurado e integrado com autenticação a uma instância Hasura, então quando você estiver pronto para fazer seus próprios projetos, você pode usar isso como modelo! https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth-template


Se você ainda não está pronto para o mundo de autenticação web3, também pode usar https://github.com/CloudNativeEntrepreneur/sveltekit-oidc , que vem pré-configurado para se conectar ao seu cluster de desenvolvimento local e uma instância do Keycloak configurada dentro isto. Vendo como ambos os projetos emitem JWTs, o objetivo é que o sistema de autenticação seja intercambiável - use web3auth ou OIDC clássico - o uso upstream dos tokens é o mesmo.


Agora vá e faça alguns dApps híbridos com APIs GraphQL geradas automaticamente e RBAC robusto e permissões e assinaturas e páginas SSR autenticadas e loops de atualização silenciosa e tokens de atualização rotativos e outras coisas!

Conclusão

Concluindo, não, JWTs e login com Ethereum/metamask não são mutuamente exclusivos. Na verdade, se você gosta da produtividade do desenvolvedor e da integração com as ferramentas existentes, acho que se sairá muito bem usando JWTs E web3auth.


Felicidades!


Estou disponível para consultoria! Se você estiver interessado em minha ajuda em um projeto em que está trabalhando, envie-me uma mensagem no Twitter!