He creado un flujo de inicio de sesión que autentica una aplicación del lado del cliente (escrita en Vue.js) para recuperar la user_api_key de un usuario de Discourse, siguiendo las directrices escritas por @samaquí.
La autenticación funciona, pero mi preocupación es almacenar la clave privada de forma segura. Por el momento, la clave privada se almacena localmente en el archivo .env y se utiliza para el cifrado/descifrado de la carga útil. ¿Es esta una forma segura de cifrar la carga útil y, si no lo es, qué alternativas existen para una aplicación de JavaScript del lado del cliente?
¿Como en una aplicación de Electron/Tauri? No tengo idea de qué elegirías; supongo que tienen algún mecanismo para almacenamiento seguro. Quizás, si tienes suerte, puedas usar el llavero en macOS y algo similar en Windows.
Es una aplicación web alojada en un servidor. La preocupación es que, de alguna manera, la carga útil podría ser interceptada si se expone la clave privada. Soy consciente de que esta es una preocupación más general con el cifrado en JavaScript, pero pregunto por si existe una práctica más segura para autenticar una aplicación web desde Discourse.
El sistema de claves de API de usuario no está diseñado para este caso de uso. Si pasas por el proceso de generar una clave privada y luego la almacenas en el servidor en nombre del usuario, ¿para qué sirve todo ese proceso? Simplemente genera las claves del lado del servidor.
Me resulta muy difícil ofrecer cualquier orientación sin entender completamente cuál es el problema real con mucho más detalle. ¿Por qué no simplemente proporcionar puntos de conexión proxy en tu aplicación web y manejar toda la autenticación en tu aplicación?
Después de hablar con mi colega @owengot, aquí tienes una descripción más detallada del problema.
Existe una aplicación web basada en Vue.js que no tiene su propio componente activo en el lado del servidor. Más bien, es una aplicación web independiente que utiliza la API de Discourse, de modo que, en cierto sentido, Discourse actúa como el servidor. Los casos de uso incluyen encuestas o formularios independientes, donde el contenido se publica en temas de Discourse bajo la cuenta del usuario. Poder crear este tipo de software sin componentes personalizados en el lado del servidor parecía una arquitectura adecuada para estos casos, por lo que, idealmente, querríamos evitar hacer cualquier cosa “en el lado del servidor”.
Ahora bien, obtener una clave de API de usuario funciona como se espera, pero @owengot descubrió que el paso de generar una clave privada en JavaScript tarda mucho tiempo (hasta 10 segundos; es simplemente ineficiente en JavaScript…). Luego, encontró un truco: la misma clave privada puede usarse para varios usuarios, por lo que la almacenó en un archivo en el servidor web que también sirve los demás archivos estáticos de la aplicación web (JS, CSS, etc.). Esto lo hace rápido… pero ahora esa clave privada es (1) compartida y (2) está almacenada de forma abierta, con una URL accesible públicamente. Eso parece, hum, aterrador
Así que dije que debemos consultar al equipo de Discourse sobre las implicaciones de seguridad de este truco. Veo dos alternativas básicas:
Si esa clave privada se usa “únicamente” para cifrar la carga útil, podríamos aceptarlo, ya que también tenemos la comunicación cifrada mediante SSL/HTTPS.
Pero si conocer esa clave privada permite de alguna manera calcular la clave de API de usuario resultante que luego se usa para publicar bajo la cuenta de alguien en Discourse, por supuesto, haría que este truco fuera inaceptable.
También tengo curiosidad al respecto, ya que he comenzado a usar el software desarrollado por @owengot. Según lo que dice @tanius, ¿crees que esta es una forma segura de hacerlo, @sam?
Sí, no hagas eso. La clave privada debe ser privada por cliente.
La generación de la clave en 10 segundos es un precio que hay que pagar. Existen algunas APIs de criptografía en JavaScript que pueden hacerlo más rápido.