"Anular" una variable en ruby [duplicar]
Tengo un caso de uso en el que necesito deshacerme de algunos datos en el mismo momento en que ya no los necesito , por razones de seguridad.
Estoy escribiendo un servidor en Ruby que se ocupa de inicios de sesión y contraseñas. Utilizo BCrypt para almacenar contraseñas en mi base de datos. Mi servidor recibe la contraseña, hace un hash bcrypt con ella y luego ya no usa la contraseña original.
Conozco un tipo de ataques cibernéticos que implican el robo de datos directamente de la RAM, y me preocupa que un atacante pueda robar la contraseña de un usuario en forma de cadena sin procesar en el período de tiempo que la contraseña todavía está en la memoria. No estoy seguro de si simplemente usarlo password_in_string_form = nil
sería suficiente.
Quiero anular la variable que contiene la contraseña del usuario en el momento en que termine con ella. Por anular me refiero a algo parecido a usar / dev / null para llenar algo con ceros. El objetivo final es la destrucción irreversible de datos .
Respuestas
No estoy seguro de si simplemente usarlo
password_in_string_form = nil
sería suficiente.
No, no sería suficiente. El objeto puede o no ser recolectado como basura inmediatamente, e incluso si lo fuera, eso no hace que el contenido se borre de la memoria.
Sin embargo, a menos que se hayan congelado, las cadenas de Ruby son mutables . Por lo tanto, siempre que no congele la cadena de contraseña, puede reemplazar su contenido con ceros, caracteres aleatorios o lo que sea antes de soltarla. En particular, esto debería funcionar, sujeto a algunas salvedades, que se tratan más adelante:
(0 ... password_in_string_form.length).each do |i|
password_in_string_form[i] = ' '
end
Pero se debe tener cuidado, ya que este enfoque, que puede parecer más idomático, no funciona:
# SURPRISE! This does not reliably remove the password from memory!
password_in_string_form.replace(' ' * password_in_string_form.length)
En lugar de actualizar el contenido de la cadena de destino en el lugar, replace()
libera el contenido al asignador interno de Ruby (que no lo modifica) y elige una estrategia para el nuevo contenido en función de los detalles del reemplazo.
Sin embargo, la diferencia de efecto entre esos dos enfoques debería ser una gran señal de advertencia para usted. Ruby es un lenguaje de bastante alto nivel. Le brinda mucho apalancamiento, pero a costa del control sobre los detalles finos, como si los datos se retienen en la memoria y cuánto tiempo.
Y eso me lleva a las salvedades. Estos son los principales:
Mientras maneja la cadena de contraseña, debe tener cuidado de evitar hacer copias de ella o de cualquier parte de ella, o bien capturar todas las copias y tirarlas a la basura también. Eso requerirá algo de disciplina y atención a los detalles, porque es muy fácil hacer tales copias.
Es posible que tirar la cadena de contraseña a la papelera no sea suficiente para lograr su objetivo. También debe eliminar cualquier otra copia de la contraseña en la memoria, por ejemplo, antes de aislar la cadena de contraseña. Si la suya es una aplicación web, por ejemplo, eso incluiría el contenido de la solicitud HTTP en la que se entregó la contraseña a su aplicación, y probablemente más cadenas derivadas de ella que solo la cadena de contraseña aislada. Lo mismo se aplica a otros tipos de aplicaciones.
Es posible que las contraseñas no sean lo único que deba proteger. Si un adversario está en una posición en la que puede robar contraseñas de la memoria de la máquina host, también está en posición de robar los datos confidenciales a los que los usuarios acceden después de iniciar sesión.
Por estas y otras razones, si los requisitos de seguridad de su servidor dictan que las copias en memoria de las contraseñas de usuario se destruyan tan pronto como ya no sean necesarias, es posible que Ruby (puro) no sea un lenguaje de implementación apropiado.
Por otro lado, si un adversario obtiene suficiente acceso para extraer contraseñas de la memoria / intercambio, es probable que el juego ya haya terminado. Como mínimo, tendrán acceso a todo lo que su aplicación pueda acceder. Eso no hace que las contraseñas sean completamente discutibles, pero debe tenerlo en cuenta en su evaluación de cuánto esfuerzo dedicar a este problema.
Esto no es posible en Ruby.
Tendrá que escribir algún código específico para cada implementación (Opal, TruffleRuby, JRuby, Rubinius, MRuby, YARV, etc.) para asegurarse de eso. Dependiendo de la implementación, es posible que ni siquiera sea posible hacerlo dentro de la memoria administrada de la implementación, sin tener una pieza de memoria separada que usted mismo administre.
Es decir, probablemente necesitará una pequeña parte de código nativo que administre su propia pequeña parte de memoria nativa y la inyecte en su programa Ruby.