Almacenamiento seguro de credenciales en python

El ataque

Un posible modelo de amenaza, en el contexto del almacenamiento de credenciales, es un atacante que tiene la capacidad de:

  • inspeccionar cualquier memoria de proceso (usuario)
  • leer archivos locales (usuario)

AFAIK, el consenso sobre este tipo de ataque es que es imposible evitarlo (ya que las credenciales deben almacenarse en la memoria para que el progtwig las use), pero hay un par de técnicas para mitigarlo:

  • minimizar la cantidad de tiempo que los datos confidenciales se almacenan en la memoria
  • sobrescriba la memoria tan pronto como los datos ya no sean necesarios
  • mangle los datos en la memoria, siga moviéndolos y otra seguridad a través de medidas de oscuridad

Python en particular

La primera técnica es lo suficientemente fácil de implementar, posiblemente a través de un anillo de claves (es de esperar que el espacio de almacenamiento del kernel)

El segundo no se puede lograr en absoluto sin escribir un módulo en C, a mi leal saber y entender (pero me encantaría estar equivocado aquí o tener una lista de los módulos existentes)

El tercero es complicado.

En particular, siendo Python un lenguaje con capacidades muy poderosas de introspección y reflexión, es difícil evitar el acceso a las credenciales a cualquier persona que pueda ejecutar el código Python en el proceso de interpretación.

Parece haber un consenso de que no hay forma de imponer atributos privados y que los bashs de hacerlo en el mejor de los casos molestarán a otros progtwigdores que están usando su código .

La pregunta

Teniendo todo esto en cuenta, ¿cómo se almacenan las credenciales de autenticación de forma segura con python? ¿Cuáles son las mejores prácticas? ¿Se puede hacer algo con la filosofía del lenguaje “todo es público”? Sé que “todos estamos aceptando adultos aquí” , pero ¿debemos vernos obligados a elegir entre compartir nuestras contraseñas con un atacante y usar otro idioma?

Hay dos razones muy diferentes por las que puede almacenar las credenciales de autenticación:

  1. Para autenticar a su usuario: por ejemplo, solo permite que el usuario acceda a los servicios después de que el usuario se autentique en su progtwig
  2. Para autenticar el progtwig con otro progtwig o servicio: por ejemplo, el usuario inicia su progtwig que luego accede al correo electrónico del usuario a través de Internet mediante IMAP.

En el primer caso, nunca debe almacenar la contraseña (o una versión encriptada de la contraseña). En su lugar, debe codificar la contraseña con un salt de alta calidad y asegurarse de que el algoritmo de hash que usa sea computacionalmente costoso (para evitar ataques de diccionario) como PBKDF2 o bcrypt. Consulte Hashing de contraseña con sal: cómo hacerlo correctamente para obtener muchos más detalles. Si sigues este enfoque, incluso si el pirata informático recupera el token salado y de hash lento, no pueden hacer mucho con él.

En el segundo caso, se hacen varias cosas para hacer más difícil el descubrimiento secreto (como se describe en su pregunta), como:

  • Mantener los secretos encriptados hasta que se necesiten, descifrarlos bajo demanda y luego volver a encriptarlos inmediatamente después
  • Usando la asignación aleatoria de espacio de direcciones, cada vez que la aplicación se ejecuta, las claves se almacenan en una dirección diferente
  • Usando los keystores del sistema operativo
  • Usar un lenguaje “duro” como C / C ++ en lugar de un lenguaje introspectivo basado en VM, como Java o Python

Tales enfoques son ciertamente mejores que nada, pero un pirata informático experto lo romperá tarde o temprano.

Fichas

Desde una perspectiva teórica, la autenticación es el acto de demostrar que la persona desafiada es quien dice ser. Tradicionalmente, esto se logra con un secreto compartido (la contraseña), pero hay otras formas de probarte a ti mismo, incluyendo:

  • Autenticación fuera de banda . Por ejemplo, donde vivo, cuando bash iniciar sesión en mi banco de Internet, recibo una contraseña única (OTP) como un SMS en mi teléfono. En este método, demuestro que soy el propietario de un número de teléfono específico
  • Token de seguridad : para iniciar sesión en un servicio, tengo que presionar un botón en mi token para obtener una OTP que luego uso como mi contraseña.
  • Otros dispositivos:

    • SmartCard , en particular como la utiliza el Departamento de Defensa de los Estados Unidos, donde se denomina CAC . Python tiene un módulo llamado pyscard para interactuar con este
    • Dispositivo NFC

Y una lista más completa aquí.

La similitud entre todos estos enfoques es que el usuario final controla estos dispositivos y los secretos nunca dejan el token / tarjeta / teléfono y, por lo tanto, nunca se almacenan en su progtwig. Esto los hace mucho más seguros.

Robo de sesion

Sin embargo (siempre hay un sin embargo):

Supongamos que usted logra asegurar el inicio de sesión para que el pirata informático no pueda acceder a los tokens de seguridad. Ahora su aplicación está felizmente interactuando con el servicio seguro. Desafortunadamente, si el pirata informático puede ejecutar ejecutables arbitrarios en su computadora, el pirata informático puede secuestrar su sesión, por ejemplo, inyectando comandos adicionales en su uso válido del servicio. En otras palabras, si bien ha protegido la contraseña, es totalmente irrelevante porque el pirata informático aún obtiene acceso al recurso ‘seguro’.

Esta es una amenaza muy real, ya que los múltiples ataques de secuencias de comandos entre sitios tienen progtwigs (un ejemplo son los sitios web de US Bank y Bank of America Vulnerables , pero hay muchos más).

Proxy seguro

Como se mencionó anteriormente, existe un problema fundamental al mantener las credenciales de una cuenta en un servicio o sistema de terceros para que la aplicación pueda iniciar sesión en ella, especialmente si el único método de inicio de sesión es un nombre de usuario y una contraseña.

Una forma de mitigar esto parcialmente delegando la comunicación al servicio a un proxy seguro y desarrollando un enfoque de inicio de sesión seguro entre la aplicación y el proxy. En este enfoque

  • La aplicación utiliza un esquema PKI o una autenticación de dos factores para iniciar sesión en el proxy seguro
  • El usuario agrega credenciales de seguridad al sistema de terceros al proxy seguro. Las credenciales nunca se almacenan en la aplicación.
  • Más tarde, cuando la aplicación necesita acceder al sistema de terceros, envía una solicitud al proxy. El proxy inicia sesión utilizando las credenciales de seguridad y realiza la solicitud, devolviendo los resultados a la aplicación.

Las desventajas de este enfoque son:

  • Es posible que el usuario no quiera confiar en el proxy seguro con el almacenamiento de las credenciales
  • El usuario no puede confiar en el proxy seguro con los datos que fluyen a través de él a la aplicación de terceros
  • El propietario de la aplicación tiene infraestructura adicional y costos de hospedaje para ejecutar el proxy

Algunas respuestas

Entonces, en respuestas específicas:

¿Cómo se almacena de forma segura las credenciales de autenticación mediante Python?

  • Si almacena una contraseña para que la aplicación autentique al usuario, use un algoritmo PBKDF2, como https://www.dlitz.net/software/python-pbkdf2/
  • Si almacena una contraseña / token de seguridad para acceder a otro servicio, entonces no existe una forma absolutamente segura.
  • Sin embargo, considere cambiar las estrategias de autenticación a, por ejemplo, la tarjeta inteligente, utilizando, por ejemplo, pyscard . Puede usar tarjetas inteligentes para autenticar a un usuario en la aplicación y también para autenticar la aplicación de manera segura en otro servicio con certificados X.509.

¿Se puede hacer algo con la filosofía del lenguaje “todo es público”? Sé que “todos estamos aceptando adultos aquí”, pero ¿debemos vernos obligados a elegir entre compartir nuestras contraseñas con un atacante y usar otro idioma?

En mi humilde opinión, no hay nada de malo en escribir un módulo específico en Python que haga lo más malditamente posible para ocultar la información secreta, lo que lo convierte en un problema correcto para que otros la reutilicen (molestar a otros progtwigdores es su propósito ). Incluso podrías codificar grandes porciones en C y vincularlas. Sin embargo, no hagas esto por otros módulos por razones obvias.

En última instancia, sin embargo, si el pirata informático tiene control sobre la computadora, no hay privacidad en la computadora en absoluto. El peor de los casos teóricos es que su progtwig se está ejecutando en una máquina virtual, y el pirata informático tiene acceso completo a toda la memoria de la computadora, incluida la BIOS y la tarjeta gráfica, y puede pasar a través de la autenticación de la aplicación para descubrir sus secretos.

Dado que no hay privacidad absoluta, el rest es solo una ofuscación, y el nivel de protección es simplemente lo difícil que es ofuscado en comparación con lo mucho que un pirata informático experto quiere la información. Y todos sabemos cómo termina eso , incluso para hardware personalizado y productos de mil millones de dólares .

Usando el llavero de Python

Si bien esto administrará la clave de forma bastante segura con respecto a otras aplicaciones, todas las aplicaciones de Python comparten el acceso a los tokens. Esto no es en lo más mínimo seguro para el tipo de ataque que le preocupa.

No soy un experto en este campo y realmente estoy tratando de resolver el mismo problema que usted, pero parece que algo así como la Bóveda de Hashicorp podría ayudar bastante bien.

En particular, WRT al problema de almacenar las credenciales para los servicios de la tercera parte. p.ej:

En el mundo moderno de todo basado en API, muchos sistemas también admiten la creación programática de credenciales de acceso. Vault se beneficia de este soporte a través de una función llamada secretos dynamics: secretos que se generan a pedido y también admiten la revocación automática.

Para Vault 0.1, Vault admite la generación dinámica de credenciales de AWS, SQL y Consul.

Más enlaces:

  • Github
  • Sitio web de Vault
  • Casos de uso