paint-brush
¡AYUDA! ¡Hay un JWT en mi metaverso!por@patrickleet
1,709 lecturas
1,709 lecturas

¡AYUDA! ¡Hay un JWT en mi metaverso!

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

Demasiado Largo; Para Leer

El advenimiento de Web3 y la difusión del uso de billeteras llevará a los usuarios a abandonar los sistemas de cuentas tradicionales basados en correo electrónico/contraseña y, en su lugar, iniciar sesión con su billetera. Los JWT, aunque un poco confusos al principio, son increíblemente útiles para los ingenieros de back-end, especialmente los de sistemas de microservicios. La multitud de "Tornillo-JWT" sugiere usar ID de sesión simples, pero esto es un paso atrás a principios de la década de 2000, cuando las arquitecturas simples en capas eran el estándar, que no tenían las complejidades de los sistemas de back-end de hoy. Patrick Lee Scott explora el uso de JWT en un mundo web3.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - ¡AYUDA! ¡Hay un JWT en mi metaverso!
Patrick Lee Scott HackerNoon profile picture

¿Están realmente muertos los JWT, o simplemente son malentendidos?

He visto bastantes artículos últimamente que sugieren que la llegada de Web3 y el uso generalizado de billeteras llevará a los usuarios a abandonar los sistemas tradicionales de cuentas basados en correo electrónico/contraseña y, en su lugar, iniciar sesión con su billetera.


Para ser honesto, después de usar algunas dApps, el flujo de trabajo súper simple de un clic o dos de su billetera que aparece es una experiencia superior.


Muchos de estos artículos continúan diciendo "¡sí, ya no necesitamos JWT!".


Aquí es donde no estoy de acuerdo.


Los JWT, aunque un poco confusos al principio, son increíblemente útiles para los ingenieros de back-end, especialmente los de sistemas de microservicios. ¡ Especialmente , considerando que estos sistemas, una gran cantidad de ellos, ya existen y ya se integran con JWT! Ethereum es genial y todo eso, pero realmente no necesitamos reinventar la rueda. Es bueno poder continuar usando las mismas herramientas de back-end a las que está acostumbrado cuando lo necesita.


Iniciar sesión con MetaMask demuestra que eres tú, pero ¿cómo demuestras a futuras llamadas a la API que eres tú?


La multitud de "tornillos JWT" sugiere usar ID de sesión simples, pero esto es un paso atrás a principios de la década de 2000, fíjate, cuando las arquitecturas simples en capas eran el estándar, que no tenían las complejidades de los sistemas de back-end de hoy.


Desafortunadamente, las ID de sesión no se pueden verificar sin un viaje de ida y vuelta adicional a la base de datos para determinar si la ID de sesión otorgada pertenece o no a una sesión válida. Esto significa que cuando el servicio de back-end recibe la solicitud que contiene el ID de la sesión, realiza una solicitud al servidor de autenticación preguntando "¿está activo?", y luego todos los demás servicios en el sistema de microservicio preguntan lo mismo.


Si hay varios servicios involucrados, podrían ser varios viajes de ida y vuelta adicionales al servicio de autenticación.


Para remediar esta situación, los expertos en criptografía se pusieron a pensar.


Lo que se les ocurrió fue JWT, ahora parte del estándar OpenID, ya sabes, el que Keycloak, Auth0 y otros te ayudan a implementar.

JWT, todos ustedes

La solución fue otorgar un conjunto de tokens: JSON Web Tokens para ser precisos. Ese conjunto consta de un AccessToken , un RefreshToken y un IdToken . Estos tokens fueron luego "firmados" por un secreto, generalmente llamado ClientSecret . La firma, solo para que estemos en la misma página, es un algoritmo hash criptográfico, en el caso de JWT, generalmente HS256 (el valor predeterminado para Auth0). En el caso de HS256 ClientSecret se usa como entrada y, por lo tanto, se convierte en la clave necesaria para descifrar con éxito ese hash, o "verificarlo". Con RS256 y ES256 se utiliza un par de claves pública/privada, es decir, firmada por clave privada y verificada con clave pública en el cliente.


Esto significa que si un servicio de back-end recibe uno de estos tokens y conoce ClientSecret , puede verificar que el servicio de autenticación que firmó ese token realmente emitió el token. El token que se usa al intentar acceder a un servicio de backend es AccessToken . Estos tokens contienen específicamente información sobre quién es el usuario, así como sus "reclamos" o, en otras palabras, qué se les permite hacer en formato para el sistema que se ocupa de ellos.


Para los sistemas de microservicios, esto significa que cada servicio que se preocupa por verificar la identidad solo necesita conocer el ClientSecret , ya que pueden verificar que el JWT es auténtico usándolo, en lugar de un viaje de ida y vuelta a la base de datos. En un sistema con muchos microservicios, esto puede reducir muchos viajes de ida y vuelta adicionales a la base de datos, lo que hace que todo el sistema sea más escalable.


Los tokens de acceso, si son robados, pueden usarse de manera malintencionada y, por esa razón, es importante tomar las precauciones adecuadas al diseñar un sistema para usarlos.


El conjunto mínimo de precauciones, además de firmar y verificar los tokens, consiste en:


  1. Establecer una fecha de caducidad en el token de acceso JWT de 5 a 15 minutos y asegurarse de que los tokens no caduquen cuando se reciban

  2. No almacene el token de acceso excepto en la memoria

  3. Emita tokens de actualización que pueden almacenarse y enviarse a un servidor para su verificación, y actualizarse junto con el ClientSecret y el ClientId que lo emitió.

  4. Usar solo cuando se transmite a través de conexiones TLS (HTTPS)

  5. Use cookies HTTP Only para que no se puedan modificar en el lado del navegador

  6. Configuración de CORS

  7. Se DEBE utilizar una clave del mismo tamaño que la salida hash (por ejemplo, 256 bits para "HS256") o mayor con este algoritmo. - RFC7518 , nota: Auth0 usa 512 bits para HS256.


Un cliente confidencial necesita un servidor intermediario, como Node.js; este servidor es un proxy para el servicio de autenticación, por lo que el cliente no necesita conocer el secreto del cliente. Un cliente público expone el secreto del cliente y no hay un servidor proxy entre el navegador y el servicio de autenticación. Esto se puede restringir aún más con la configuración de CORS para que solo se permitan solicitudes de ciertos dominios.


Las precauciones adicionales incluyen:


  1. Use tokens de actualización rotativos: cada uno solo se puede usar una vez. Cuando se usa, se intercambia por un conjunto completamente nuevo de tokens y se revoca el token de actualización intercambiado. Si se emplea esta estrategia, vale la pena señalar que los usuarios con una conexión a Internet deficiente a veces pueden no recibir la respuesta a la solicitud de actualización y volver a intentarlo. Por esta razón, un breve período de gracia de aproximadamente 30 segundos les permitirá actualizar y volver a intentarlo.
  2. Permitir que el usuario revoque todos sus tokens de actualización existentes al cerrar la sesión.


Y probablemente más, por ejemplo, si detecta que alguien intenta usar un token de actualización revocado, podría revocar todos los tokens de actualización activos de ese usuario.


Es cierto que todas estas precauciones pueden hacer que hacerlo bien sea un poco difícil. Hay mucho que entender. También hay problemas de usabilidad. Un usuario que se desconecta de su sitio cada 5 minutos se sentiría bastante molesto para ellos. Para evitar esto, se debe implementar un bucle de actualización silencioso en la aplicación consumidora para actualizar continuamente el conjunto de tokens.


Dicho esto, por el otro lado de hacerlo bien, es poder integrarse de forma segura con todos sus sistemas back-end de manera escalable, así como con muchas herramientas existentes, como Hasura , que puede generar automáticamente todas sus API basadas en un esquema DB de Postgres conectado. Por lo tanto, ser capaz de integrarse fácilmente con las herramientas existentes puede ahorrar mucho tiempo de desarrollo.


Si ya usa OpenId, es probable que ya tenga estas cosas en su lugar. Es, después de todo, un estándar de autenticación.


Entonces, ¿cómo podemos mantener la conveniencia de usar JWT en un Web3 e iniciar sesión con el mundo MetaMask?

JWT y Web3?

Comencemos por entender el flujo de autenticación de OpenId que se usa para SSO.


  1. Visita un sitio web y desea iniciar sesión con su cuenta; hace clic en el botón de inicio de sesión
  2. Se le redirige a la página de inicio de sesión de SSO: inicia sesión con un correo electrónico/nombre de usuario y contraseña
  3. Se le redirige a la aplicación original con un conjunto de JWT que se almacenan adecuadamente y se utilizan en flujos de fondo de actualización silenciosa.


En el mundo de web3auth, estamos reemplazando el paso dos con el uso de los pares de claves pública y privada de su billetera para firmar un desafío. La redirección no es necesaria ni deseada.


  1. Visita un sitio web y desea iniciar sesión con su cuenta; hace clic en el botón de inicio de sesión

  2. Recibe un desafío del servidor de autenticación que abre su billetera y le pide que "Firme" el desafío. Señal de prensa.

  3. El servidor de autenticación verifica su firma y le emite un conjunto de JWT que se almacenan adecuadamente y se utilizan en flujos de fondo de actualización silenciosa.



Simplemente estamos reemplazando el flujo de redirección de estilo SSO con un desafío que está firmado por su billetera. El flujo después de recibir los tokens sigue siendo el mismo que OpenID. Eso significa que podría, por ejemplo, cambiar de usar OpenID a usar web3auth con un servidor emisor de JWT, y no tendría que cambiar nada sobre el uso de esos tokens después de que se otorgan. Todas sus integraciones de back-end existentes con herramientas como Hasura siguen siendo exactamente las mismas.


Esto es exactamente lo que quiero como desarrollador de ciclo completo. No quiero reinventar la rueda. Quiero reemplazar OpenID con web3auth y aún poder usar todas las poderosas herramientas a las que estoy acostumbrado.


Desafortunadamente, no pude encontrar un servidor web3auth que hiciera esto tan bien como las precauciones de seguridad. Encontré algunos proyectos que demuestran técnicas en el proceso, pero no todo el flujo de principio a fin.


Así que me puse a construir…


Construí este servidor de autenticación aquí: https://github.com/CloudNativeEntrepreneur/web3auth-service


Y esta aquí la integración de SvelteKit para acompañarlo, que implementa todas las cosas: actualización silenciosa, yada yada, todas esas cosas que mencioné anteriormente: https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth


Por supuesto, si iba a haber un cliente GraphQL y un ejemplo, entonces también tenía que haber un servidor GraphQL y una base de datos, así que también proporcioné ejemplos de eso: https://github.com/CloudNativeEntrepreneur/example-hasura + https: //github.com/CloudNativeEntrepreneur/example-readmodel


Este ejemplo usa el operador Zalando Postgres y SchemaHero , por lo que todo lo que necesita hacer es declarar sus bases de datos y describir su esquema en YAML, y Hasura generará automáticamente todas las API de GraphQL que necesita. Y creé el servidor de autenticación con Hasura en mente, por lo que tiene los reclamos adecuados para integrarse con el RBAC y los permisos de Hasura, que son bastante sólidos.


Y, por supuesto, necesita un lugar para ejecutar todo eso y, por lo tanto, un clúster de desarrollo local que configure todas las herramientas como istio, los operadores y SchemaHero para usted. https://github.com/CloudNativeEntrepreneur/local-dev-cluster


Pero, ¿quién sabe cómo usar todo eso?


Por eso hice este meta repositorio: https://github.com/CloudNativeEntrepreneur/web3auth-meta


El uso de ese meta repositorio clonará todos los proyectos que necesita en los lugares correctos y los ejecutará todos juntos.


Finalmente, para ejecutar todos los proyectos juntos, necesita herramientas instaladas, y la instalación de herramientas es molesta, ¡así que hice este repositorio aquí que las instalará todas por usted! https://github.com/CloudNativeEntrepreneur/a bordo


También publiqué sveltekit-web3auth en npm e hice una plantilla a partir de un proyecto SvelteKit que lo usa y tiene GraphQL configurado e integrado con autenticación en una instancia de Hasura, de modo que cuando esté listo para hacer sus propios proyectos, puede usar eso. como plantilla! https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth-template


Si aún no está listo para el mundo de la autenticación web3, también puede usar https://github.com/CloudNativeEntrepreneur/sveltekit-oidc , que viene preconfigurado para conectarse a su clúster de desarrollo local y una instancia de Keycloak que está configurada dentro eso. Dado que ambos proyectos emiten JWT, el objetivo es que el sistema de autenticación sea intercambiable: use web3auth o OIDC clásico; el uso ascendente de los tokens es el mismo.


¡Ahora vaya y cree algunas dApps híbridas con API GraphQL autogeneradas y RBAC robusto y permisos y suscripciones y páginas SSR autenticadas y bucles de actualización silenciosos y tokens de actualización rotativos y esas cosas!

Conclusión

En conclusión, no, los JWT y el inicio de sesión con Ethereum/metamask no son mutuamente excluyentes. De hecho, si le gusta la productividad del desarrollador y la integración con las herramientas existentes, creo que lo hará bastante bien usando JWT Y web3auth.


¡Salud!


¡Estoy disponible para consultas! Si estás interesado en mi ayuda en un proyecto en el que estás trabajando, ¡envíame un mensaje en Twitter!