¿Se puede considerar seguro el almacenamiento local? [cerrado]

161

Estoy obligado a desarrollar una aplicación web que funcione sin conexión durante largos períodos. Para que esto sea viable, no puedo evitar guardar datos confidenciales (datos personales pero no el tipo de datos que solo almacenaría hash) en el almacenamiento local.

Acepto que esto no es una práctica recomendada, pero con pocas opciones, estoy haciendo lo siguiente para proteger los datos:

  • cifrando todo lo que va al almacenamiento local utilizando la biblioteca criptográfica de JavaScript de Stanford y AES-256
  • la contraseña del usuario es la clave de cifrado y no está almacenada en el dispositivo
  • sirviendo todo el contenido (cuando está en línea) desde un único servidor confiable a través de SSL
  • validando todos los datos que van y vienen del almacenamiento local en el servidor usando el proyecto owasp antisamy
  • en la sección de red de appcache, sin usar *, y en su lugar enumerando solo los URI necesarios para la conexión con el servidor de confianza
  • en general tratando de aplicar las pautas sugeridas en la hoja de trucos OWASP XSS

Aprecio que el diablo a menudo está en los detalles, y sé que hay mucho escepticismo sobre el almacenamiento local y la seguridad basada en JavaScript en general. ¿Alguien puede comentar si hay:

  • defectos fundamentales en el enfoque anterior?
  • ¿Alguna solución posible para tales defectos?
  • ¿Alguna mejor manera de asegurar el almacenamiento local cuando una aplicación html 5 debe funcionar sin conexión durante largos períodos?

Gracias por cualquier ayuda.

usuario1173706
fuente
"Acepto que esta no es una práctica recomendada" - ¿Es así? ¿No es lo contrario de lo que realmente se ha creado para eso?
Hakre
2
Para aclarar, quise decir práctica no recomendada para almacenar datos confidenciales en el almacenamiento local.
user1173706
¿No debería pasar datos confidenciales a través de redes grandes?
hakre
@ user1173706 ¿Por qué la aplicación tiene que funcionar tiene que ejecutarse durante largos períodos de tiempo sin conexión? ¿Cómo son los usuarios? ¿Qué navegadores tienes que soportar? Por mi parte, creo que es posible, pero necesito saber detalles sobre su escenario.
Benjamin Gruenbaum
@Benjamin, he actualizado la pregunta. Gracias.
user1173706

Respuestas:

74

WebCrypto

Las preocupaciones con la criptografía en JavaScript del lado del cliente (navegador) se detallan a continuación. Todas menos una de estas preocupaciones no se aplican a la API de WebCrypto , que ahora es razonablemente compatible .

Para una aplicación sin conexión, aún debe diseñar e implementar un almacén de claves seguro.

Aparte: si está utilizando Node.js, use la API de cifrado incorporada .

Criptografía Native-Javascript (pre-WebCrypto)

Supongo que la principal preocupación es alguien con acceso físico a la computadora que lee localStoragesu sitio y desea criptografía para evitar ese acceso.

Si alguien tiene acceso físico, también está abierto a otros ataques y algo peor que leer. Estos incluyen (pero no se limitan a): registradores de teclas, modificación de script fuera de línea, inyección de script local, envenenamiento de caché del navegador y redireccionamientos de DNS. Esos ataques solo funcionan si el usuario usa la máquina después de haber sido comprometida. Sin embargo, el acceso físico en tal escenario significa que tiene mayores problemas.

Tenga en cuenta que el escenario limitado en el que la criptografía local es valiosa sería si se roba la máquina.

Hay bibliotecas que implementan la funcionalidad deseada, por ejemplo, Stanford Javascript Crypto Library . Sin embargo, hay debilidades inherentes (como se menciona en el enlace de la respuesta de @ ircmaxell):

  1. Falta de entropía / generación de números aleatorios;
  2. La falta de un almacén de claves seguro, es decir, la clave privada debe estar protegida con contraseña si se almacena localmente o en el servidor (que impide el acceso sin conexión);
  3. Falta de borrado seguro;
  4. Falta de características de tiempo.

Cada una de estas debilidades corresponde a una categoría de compromiso criptográfico. En otras palabras, si bien puede tener "cripto" por nombre, estará muy por debajo del rigor al que uno aspira en la práctica.

Dicho todo esto, la evaluación actuarial no es tan trivial como "Javascript crypto es débil, no lo use". Esto no es un endoso, estrictamente una advertencia y requiere que comprenda completamente la exposición de las debilidades anteriores, la frecuencia y el costo de los vectores que enfrenta, y su capacidad de mitigación o seguro en caso de falla: Javascript crypto, en a pesar de sus debilidades, puede reducir su exposición, pero solo contra ladrones con capacidad técnica limitada. Sin embargo, debe suponer que la criptografía Javascript no tiene valor contra un atacante determinado y capaz que se dirige a esa información. Algunos considerarían engañoso llamar a los datos "encriptados" cuando se sabe que hay tantas debilidades inherentes a la implementación. En otras palabras, puede disminuir marginalmente su exposición técnica, pero aumenta su exposición financiera de la divulgación. Cada situación es diferente, por supuesto, y el análisis para reducir la exposición técnica a la exposición financiera no es trivial. Aquí hay una analogía ilustrativa:Algunos bancos requieren contraseñas débiles , a pesar del riesgo inherente, porque su exposición a pérdidas por contraseñas débiles es menor que los costos para el usuario final de soportar contraseñas seguras.

🔥 Si leyó el último párrafo y pensó "Un tipo en Internet llamado Brian dice que puedo usar Javascript crypto", no use Javascript crypto.

Para el caso de uso descrito en la pregunta, parece tener más sentido que los usuarios cifren su partición local o directorio de inicio y usen una contraseña segura. Ese tipo de seguridad es generalmente bien probado, ampliamente confiable y comúnmente disponible.

Brian M. Hunt
fuente
Hay documentación adicional (citas) disponible para la postura general de "no usar criptografía JavaScript" proporcionada por el Grupo NCC desde 2011: Criptografía JavaScript considerada dañina (especialmente debido a la trampa-22 de descargar la herramienta para verificar las descargas ... calidad PRNG ... etc.)
amcgregor
58

Bueno, la premisa básica aquí es: no, todavía no es seguro.

Básicamente, no puede ejecutar crypto en JavaScript: JavaScript Crypto Considerado Dañino .

El problema es que no puede ingresar de manera confiable el código criptográfico en el navegador, e incluso si pudiera, JS no está diseñado para permitirle ejecutarlo de manera segura. Por lo tanto, hasta que los navegadores tengan un contenedor criptográfico (que proporcionan las Extensiones de Medios Cifrados, pero se están reuniendo para sus propósitos de DRM), no será posible hacerlo de forma segura.

En cuanto a una "Mejor manera", no hay una en este momento. Su única alternativa es almacenar los datos en texto plano y esperar lo mejor. O no almacene la información en absoluto. De cualquier manera.

O eso, o si necesita ese tipo de seguridad, y necesita almacenamiento local, cree una aplicación personalizada ...

ircmaxell
fuente
8
Downvoter: ¿puedes dar una mejor respuesta? Me doy cuenta de que este es un tema un tanto controvertido donde hay un desacuerdo significativo entre los profesionales de seguridad (y también los no profesionales), por lo que valdría la pena compartir el punto de vista alternativo. A menos que esté votando por otra razón, en cuyo caso, ¿cómo puedo mejorar esta respuesta?
ircmaxell
9
@ircmaxell no soy yo, pero no estoy de acuerdo con esta respuesta. "El problema es que no se puede ingresar de manera confiable el código criptográfico en el navegador, e incluso si se pudiera, JS no está diseñado para permitirle ejecutarlo de manera segura". - ¿Por qué? ¿Cuál es el problema inherente ? Puede usar la biblioteca de cifrado JavaScript de Stanford y cifrar / descifrar en ella. Puedes hacer hash y puedes hacer todo de forma segura. No veo el problema inherente aquí en una aplicación fuera de línea en JS que hace crpyto estándar, al igual que lo haría una aplicación construida en cualquier otro idioma.
Benjamin Gruenbaum
11
@BenjaminGruenbaum: el problema es que hay varios lugares donde ese código criptográfico necesitaría interactuar con código de terceros. El punto principal de ese artículo al que me vinculé es que no puedes controlar el entorno de ejecución. Entonces instalas la Stanford Crypto lib. Entonces, ¿qué sucede si algún complemento del navegador anula el sjcl.encryptenvío de la clave al atacante? En JS eso es 100% posible y no hay nada que puedas hacer para detenerlo. Y ese es el punto subyacente. No existen mecanismos de "seguridad" para evitar que otros JS hagan cosas desagradables a sus datos. Y eso es un problema .
ircmaxell
13
@ircmaxell Si duermes con perros, no puedes esperar no despertarte con pulgas. Si el usuario instala un complemento de malware que es igual que el usuario que instala un virus en su PC, no es diferente. Su programa Java o C puede ser tan seguro como sea posible, pero tan pronto como el atacante tenga la capacidad de ejecutar el código, está jodido. Eso no es diferente para JS. Los complementos no solo aparecen mágicamente en el navegador. Además, no guardar la información encriptada no ayudaría de ninguna manera si el usuario tiene malware, ya que podría secuestrar los datos en vivo.
Benjamin Gruenbaum
9
@BenjaminGruenbaum: en desacuerdo. En una aplicación normal, lo que se necesita , ya sea poner en peligro la propia aplicación (para leer las posiciones de memoria), o acceso a la raíz de ganancia a la caja (comprometer el sistema operativo). De cualquier manera, debe comprometer algo más profundo que simplemente hacer un comportamiento normal. JS permite esto en el comportamiento normal. Cuál es el problema ...
ircmaxell
12

Como exploración de este tema, tengo una presentación titulada "Asegurando TodoMVC usando la API de criptografía web" ( video , código ).

Utiliza la API de criptografía web para almacenar la lista de tareas cifrada en localStorage mediante una contraseña que protege la aplicación y utiliza una clave derivada de la contraseña para el cifrado. Si olvida o pierde la contraseña, no hay recuperación. ( Descargo de responsabilidad: era un POC y no estaba destinado para uso de producción ) .

Como dicen las otras respuestas, esto todavía es susceptible a XSS o malware instalado en la computadora cliente. Sin embargo, cualquier dato confidencial también estará en la memoria cuando los datos estén almacenados en el servidor y la aplicación esté en uso. Sugiero que el soporte fuera de línea puede ser un caso de uso convincente.

Al final, el cifrado de localStorage probablemente solo protege los datos de los atacantes que tienen acceso de solo lectura al sistema o sus copias de seguridad. Agrega una pequeña cantidad de defensa en profundidad para la exposición de datos sensibles al elemento A6 de OWASP Top 10 , y le permite responder "¿Alguno de estos datos se almacena en texto claro a largo plazo?" correctamente.

Kevin Hakanson
fuente
3

Este es un artículo realmente interesante aquí. Estoy considerando implementar el cifrado JS para ofrecer seguridad al usar almacenamiento local. Está absolutamente claro que esto solo ofrecerá protección si el dispositivo es robado (y se implementa correctamente). No ofrecerá protección contra keyloggers, etc. Sin embargo, este no es un problema de JS ya que la amenaza keylogger es un problema de todas las aplicaciones, independientemente de su plataforma de ejecución (navegador, nativo). En cuanto al artículo "Crypto de JavaScript considerado dañino" al que se hace referencia en la primera respuesta, tengo una crítica; dice "Puedes usar SSL / TLS para resolver este problema, pero eso es costoso y complicado". Creo que este es un reclamo muy ambicioso (y posiblemente bastante parcial). Sí, SSL tiene un costo,

Mi conclusión: hay un lugar para el código de cifrado del lado del cliente, sin embargo, como con todas las aplicaciones, los desarrolladores deben reconocer sus limitaciones e implementar si es adecuado para sus necesidades, y asegurarse de que haya formas de mitigar sus riesgos.

Paul S
fuente
Históricamente ha habido costos extraordinarios (mecánicos, no financieros) asociados con la negociación de conexión inicial. Hasta el punto de que las corporaciones utilizarían dispositivos de terminación SSL dedicados, lo que podría ser financieramente costoso más allá de la emisión de certificados y los costos de garantía. Hoy en día, muchos de esos problemas se han resuelto, como la persistencia de la sesión de duración extendida para evitar el apretón de manos inicial en solicitudes posteriores.
amcgregor
2

No es accesible a ninguna página web (verdadero) pero es fácilmente accesible y fácilmente editable a través de herramientas de desarrollo, como chrome (ctl-shift-J). Por lo tanto, se requiere una criptografía personalizada antes de almacenar el valor.

Pero, si JavaScript necesita descifrar (para validar), el algoritmo de descifrado queda expuesto y puede manipularse.

Javascript necesita un contenedor totalmente seguro y la capacidad de implementar adecuadamente variables y funciones privadas que estén disponibles solo para el intérprete js. Pero esto viola la seguridad del usuario, ya que los datos de seguimiento se pueden usar con impunidad.

En consecuencia, javascript nunca será completamente seguro.

rockmo
fuente
-29

No.

Se puede acceder a localStorage desde cualquier página web, y si tiene la clave, puede cambiar los datos que desee.

Dicho esto, si puede idear una forma de cifrar las claves de forma segura, no importa cómo transfiera los datos, si puede contener los datos dentro de un cierre, entonces los datos son (algo) seguros.

hellol11
fuente
19
No es accesible a "ninguna página web". Solo es accesible a las páginas en el dominio actual.
dtabuenc
@dtabuenc, por el contrario, hice un lapicero hace un tiempo que le muestra cada par clave / valor en su almacenamiento local , sin ningún truco .
hellol11
3
No! Lo siento. El almacenamiento local está aislado por dominio. El código que se ejecuta en un dominio no puede acceder a los valores que otro dominio almacenó en el almacenamiento local. Por ejemplo, google.com almacena un montón de cosas en el almacenamiento local. No podrá enumerar ninguna de las claves de google.com en su ejemplo de lápiz.
dtabuenc
@dtabuenc lo probó, tienes razón.
hellol11