Mi pregunta tiene que ver con la seguridad de JavaScript.
Imagine un sistema de autenticación en el que utiliza un marco de JavaScript como Backbone o AngularJS , y necesita puntos finales seguros. Eso no es un problema, ya que el servidor siempre tiene la última palabra y verificará si está autorizado para hacer lo que quiera.
Pero, ¿y si necesita un poco de seguridad sin involucrar al servidor? ¿Es eso posible?
Por ejemplo, supongamos que tiene un sistema de enrutamiento del lado del cliente y desea proteger una ruta concreta para los usuarios registrados. Entonces haces ping al servidor preguntando si puedes visitar rutas protegidas y continúas. El problema es que cuando hace ping al servidor, almacena la respuesta en una variable, por lo que la próxima vez que vaya a una ruta privada, comprobará si ya ha iniciado sesión (no hay ping al servidor), y dependiendo en la respuesta irá o no.
¿Qué tan fácil es para un usuario modificar esa variable y obtener acceso?
Mi conocimiento de seguridad (y JavaScript) no es excelente. Pero si una variable no está en el alcance global y está en la parte privada de un patrón de módulo que solo tiene captadores pero no establecedores, incluso en ese caso, ¿puede hackear la cosa?
fuente
manipulate any part of the sight without long lines
sitio vs vistaRespuestas:
Lea la respuesta de Joachim antes de leer esta. Cubre las razones generales detrás de la vulnerabilidad del lado del cliente. Ahora, para una sugerencia de cómo solucionar este problema ...
Un esquema seguro para la comunicación cliente-servidor sin tener que autenticarse manualmente con el servidor en cada solicitud:
Estás todavía dejar que el servidor tiene la última palabra, y el servidor todavía tiene que validar todo lo que el cliente dice, pero sucede de forma transparente.
Asuma el protocolo HTTPS para prevenir ataques de hombre en el medio (MITMA).
El cliente se da la mano con el servidor por primera vez, y el servidor genera una clave pública para el cliente y mantiene una privada utilizando un esquema de cifrado asimétrico. El cliente almacena la clave "pública" del servidor en el almacenamiento local, encriptada con una contraseña segura que no guarda en ningún lugar.
El cliente ahora está fuera de línea. El cliente quiere realizar acciones confiables. El cliente ingresa su contraseña y toma la clave pública del servidor.
El cliente ahora realiza acciones basadas en su conocimiento de esos datos, y el cliente cifra cada acción que realiza con la clave pública del servidor para ese cliente .
Cuando el cliente está en línea, el cliente envía su ID de cliente y todas las acciones que el cliente realizó se envían al servidor cifradas con la clave pública del servidor.
El servidor descifra las acciones y, si están en el formato correcto, confía en que se originaron en el cliente.
Nota:
No puede almacenar la contraseña del cliente en ningún lado, de lo contrario, un atacante podría obtener la clave y firmar las acciones como si fueran propias. La seguridad de este esquema se basa únicamente en la integridad de la clave que el servidor genera para el cliente. El cliente aún necesitaría ser autenticado con el servidor cuando solicite esa clave.
De hecho, todavía confía en el servidor por seguridad y no en el cliente. Cada acción que realice el cliente debe validarla en el servidor.
Es posible ejecutar scripts externos en trabajadores web . Tenga en cuenta que cada solicitud JSONP que tiene ahora es un problema de seguridad mucho mayor. Debe proteger la clave a toda costa. Una vez que lo pierde, un atacante puede suplantar al usuario.
Esto satisface su demanda de que no se realice "ping al servidor". Un atacante no puede simplemente imitar una solicitud HTTP con datos falsificados si no conoce la clave.
La respuesta de Joachim sigue siendo correcta . Todavía está, de hecho, realizando toda la autenticación en el servidor . Lo único que guardó aquí es la necesidad de validar la contraseña con el servidor cada vez. Ahora solo necesita involucrar al servidor cuando desea confirmar o extraer datos actualizados. Todo lo que hicimos aquí es guardar una clave confiable en el lado del cliente y hacer que el cliente la vuelva a validar.
Este es un esquema bastante común para aplicaciones de una sola página (por ejemplo, con AngularJS).
Llamo a la clave pública del servidor "pública" por lo que eso significa en esquemas como RSA , pero de hecho es información confidencial en el esquema y debe protegerse.
No guardaría la contraseña en ningún lugar de la memoria. Haría que el usuario envíe su contraseña 'fuera de línea' cada vez que comience a ejecutar el código fuera de línea.
No utilice su propia criptografía : use una biblioteca conocida como la de Stanford para la autenticación.
Sigue este consejo tal como está . Antes de implementar este tipo de autenticación en una aplicación crítica del mundo real, consulte a un experto en seguridad . Este es un problema grave que es doloroso y fácil de equivocar.
Es crítico que ningún otro script tenga acceso a la página. Esto significa que solo permite scripts externos con trabajadores web. No puede confiar en ningún otro script externo que pueda interceptar su contraseña cuando el usuario la ingrese.
Use un campo de contraseña en línea
prompt
y no uno si no está completamente seguro y no difiere su ejecución (es decir, no debería vivir hasta un punto donde los eventos tengan acceso a él, sino solo en el código de sincronización). Y en realidad no almacene la contraseña en una variable; de nuevo, esto solo funciona si confía en que la computadora del usuario no está comprometida (aunque eso también es cierto para validar contra un servidor).Me gustaría agregar nuevamente que todavía no confiamos en el cliente . No puedes confiar solo en el cliente, y creo que la respuesta de Joachim lo logra. Solo obtuvimos la conveniencia de no tener que hacer ping al servidor antes de comenzar a trabajar.
Material relacionado:
fuente
window.prompt
método para interceptar la frase de paso o iniciar un mensaje propio (¡posiblemente dentro de un iframe!). Un campo de contraseña tiene un beneficio adicional: los caracteres no se muestran.Es simple: cualquier mecanismo de seguridad que se base en que el cliente haga solo lo que usted le dice puede verse comprometido cuando un atacante tiene control sobre el cliente.
Usted puede tener los controles de seguridad en el cliente, pero sólo para efectivamente actuar como un "caché" (para evitar hacer una cara de ida y vuelta al servidor si el cliente ya sabe que la respuesta será "no").
Si desea mantener la información de un conjunto de usuarios, asegúrese de que el cliente de esos usuarios nunca obtenga esa información. Si envía esos "datos secretos" junto con instrucciones "pero no los muestre", será trivial deshabilitar el código que verifica esa solicitud.
Como puede ver, esta respuesta realmente no menciona ninguna especificación de JavaScript / navegador. Esto se debe a que este concepto es el mismo, sin importar cuál sea su cliente. Realmente no importa que sea un cliente pesado (aplicación cliente / servidor tradicional), una aplicación web de la vieja escuela o una aplicación de una sola página con JavaScript extenso del lado del cliente.
Una vez que sus datos salen del servidor, debe suponer que un atacante tiene acceso completo a ellos.
fuente
Hay un dicho en la comunidad de jugadores: " El cliente está en manos del enemigo". Cualquier código que se ejecute fuera de un área segura como el servidor es vulnerable. En el escenario más básico, vulnerable a no ejecutarse en primer lugar. Es la decisión del cliente ejecutar realmente su" código de seguridad "y el usuario puede simplemente "optar por salir". Mientras que con el código nativo tiene al menos una ofuscación automática en el ensamblaje y una capa adicional de protección por el hecho de que un atacante necesita ser un buen programador para manipular eso, JS normalmente viene sin obstrucciones y como texto sin formato. Todo lo que necesita para organizar un ataque son herramientas primitivas como un servidor proxy y un editor de texto. El atacante aún necesitará un cierto nivel de educación sobre programación, pero es mucho más fácil modificar un script usando cualquier editor de texto que inyectar código en un ejecutable.
fuente
No se trata de hackear JavaScript. Si quisiera atacar su aplicación, usaría un proxy privado que me permitiría capturar, modificar y reproducir el tráfico. Su esquema de seguridad propuesto no parece tener ninguna protección contra eso.
fuente
Hablando específicamente sobre Angular:
Proteger una ruta del lado del cliente simplemente no existe. Incluso si 'oculta' un botón para esa ruta, el usuario siempre puede escribirlo, Angular se quejará, pero el cliente puede codificarlo.
En algún momento, su controlador tendrá que pedirle a su servidor los datos necesarios para representar la vista, si el usuario no está autorizado para acceder a esos datos, no los recibirán ya que ha protegido estos datos en el lado del servidor , y su aplicación Angular debería manejar el 401 adecuadamente.
Si está tratando de proteger los datos sin procesar, no puede ser del lado del cliente, si solo desea que un usuario en particular solo pueda ver datos comunes de cierta manera, cree las 'vistas' de datos en el servidor en lugar de enviar datos brutos para el cliente y reorganizarlos (de todos modos, ya debería hacerlo por razones de rendimiento).
Nota al margen: nunca debe haber nada sensible integrado en las plantillas de vista que solicite Angular, simplemente no lo haga. Si por alguna extraña razón existe, debe proteger esas plantillas de vista en el lado del servidor, tal como lo haría si estuviera haciendo la representación del lado del servidor.
fuente