Cifrado de direcciones IP en una base de datos MySQL

12

Me gustaría cifrar las direcciones IP en mi base de datos MySQL, con las siguientes restricciones:

  • No necesita ser resistente a los atacantes que pueden ejecutar consultas.
  • Debe ser resistente a los atacantes que tienen acceso a los archivos en el disco.
  • Debe poder validar una IP contra el formulario encriptado, para verificar si coincide.
  • También sería útil verificar con /24 comodines (por ejemplo, 10.20.30.* ).
  • No se puede ingresar ninguna forma de clave o contraseña en el inicio del sistema, ya que se ejecutará en un servidor en un centro de datos, e iniciar sesión a través de SSH cada reinicio es un dolor que puedo prescindir.

Actualmente estoy usando conexiones de base de datos separadas para ofrecer mejores restricciones de privilegios, con una tabla separada para las contraseñas. También estoy usando MySQLi y revisiones de código semiautomatizadas para garantizar que no haya agujeros de inyección SQL.

Con un mecanismo hash sin salado (es decir, determinístico), sería fácil calcular todos los hashes IP posibles. Con un hash salado, ese problema se reduce, pero aún así no es mucho mejor si un atacante solo intenta romper un hash de IP. Por supuesto, todo esto también evita las búsquedas con comodines.

¿Hay una solución para esto?

Actualización:
Después de pensarlo, he encontrado el siguiente esquema:

  • La aplicación web tiene una clave pública RSA de 4096 bits incorporada en la fuente, mantengo la clave privada en un volumen TrueCrypt en mi máquina doméstica.
  • Al insertar entradas en la tabla de registros, la IP se rellena con una cadena aleatoria y se cifra con la clave pública. Esto hace que descifrarlo sea imposible y hace que el cifrado no sea determinista.
  • La aplicación web proporciona una API para exportar los registros, a los que solo pueden acceder mediante SSL los usuarios autenticados.
  • Escribo una aplicación para usar la API para navegar por los registros de mi equipo doméstico, usar la clave privada para descifrar las direcciones IP.
  • Cuando una dirección IP está prohibida, la IP se almacena en texto sin formato en la tabla de prohibiciones.

¿Algún comentario o sugerencia?

    
pregunta Polynomial 20.04.2012 - 18:02
fuente

5 respuestas

7

El cifrado de clave pública / privada es lento. Es ideal para escribirlo & olvídalo, pero no es un proceso rápido.

En aras de la velocidad, considere esto: use una clave simétrica generada al azar que se elige cuando se inicia el daemon y posiblemente se gire cada hora, cada día, semanalmente o mensualmente (según sus necesidades de tráfico y seguridad). Deje esa clave solo en la memoria y cifre esa clave simétrica en una tabla de base de datos con la clave pública de su par de llaves. Luego puede recuperar la clave, pero un atacante no puede obtenerla excepto al descargar la memoria de procesos. Incluso entonces, el atacante solo puede usar la clave más reciente. Es probable que desee utilizar algo para vincular las claves a los datos o tendrá que forzar su lista de claves contra cada registro. Esa grabación podría ser tan simple como la hora de inicio / parada si sus registros tienen marcas de tiempo, números de secuencia, o el inicio de entradas cifradas con un campo de identificación de clave, etc.

Independientemente del método que utilice, rellene su IP antes de cifrarla. Veo que desde que actualizó su respuesta, esto se menciona, pero es definitivamente importante para cualquiera que haga referencia a esto. Eso evitará la indexación, pero también evitará cualquier problema de "casillero" y la misma IP siempre que tenga la misma salida cifrada.

    
respondido por el Jeff Ferland 20.04.2012 - 20:20
fuente
3

Tu esquema es una buena solución. ¡Bien hecho!

Una posible optimización del rendimiento. Si necesita una manera de hacerlo más eficiente, hay formas de mejorar la eficiencia. Por ejemplo, aquí está uno. La aplicación puede seleccionar una clave simétrica aleatoria K , encriptar K bajo la clave pública, luego encriptar la dirección IP en K , y almacenar la encriptada La dirección IP y el valor cifrado de K en la base de datos.

Más adelante, cuando exporte los registros, si desea prohibir una dirección IP, ya que tiene la clave privada, puede recuperar el valor correspondiente de K y luego descifrarlo utilizando K para recuperar la dirección IP, y agregar esa dirección IP en texto sin cifrar a la lista de prohibición.

¿Cómo mejora esto el rendimiento? El truco clave es que puede reutilizar el mismo valor de K para muchas direcciones IP diferentes. Cuando se inicie, puede seleccionar K , cifrarlo bajo la clave pública y almacenar en caché el valor de K y el cifrado de K . Ahora puede reutilizarlo para muchas entradas de registro. Puede borrar periódicamente la memoria caché y crear una nueva K si lo desea. (Solo asegúrese de almacenar el valor almacenado en caché de K solo en la memoria, no en la base de datos). De esta manera, solo tiene que hacer un solo cifrado de clave pública cada cierto tiempo. Cada vez que desee registrar una nueva dirección IP, solo necesita hacer un cifrado de clave simétrica debajo de K , que debería ser muy eficiente.

Por qué la optimización puede ser innecesaria. Dicho esto, si elige su algoritmo de cifrado de clave pública correctamente, incluso su esquema básico podría ser muy eficiente. Por ejemplo, si utiliza el cifrado RSA utilizando el exponente público e = 3, el cifrado es muy rápido y el esquema que proponga puede ser lo suficientemente rápido.

    
respondido por el D.W. 21.04.2012 - 07:33
fuente
2

Su descripción no está completa, porque no le dice a quién / qué va a "validar las direcciones IP con el formulario cifrado". A partir de tu actualización, supongo que quieres:

  • para poder registrar las direcciones IP entrantes, de manera tal que un atacante que obtenga acceso de lectura completo en los archivos del servidor no pueda reconstruir las direcciones IP registradas, sino que un autor autorizado el administrador (usted) podría hacerlo;
  • para mantener un conjunto de direcciones IP "prohibidas", posiblemente incluyendo rangos, y el servidor debe poder hacer coincidir una dirección IP con ese conjunto.

Como usted (comprensiblemente) no quiere escribir una frase de contraseña o insertar una clave cada vez que se reinicia el servidor, debe asumir que un atacante que obtiene acceso completo de lectura en los archivos completos del servidor sabe todo lo que el servidor sabe inmediatamente después de una nueva actualización. comienzo. En particular, el atacante puede simular el servidor en su propia máquina. Dado que un servidor de este tipo puede decidir si una dirección IP dada está prohibida o no, el atacante puede obtener fácilmente la misma información con su simulación (después de todo, solo hay cuatro billones de direcciones IPv4). Corolario: también puede mantener las direcciones prohibidas (rangos de) en texto claro , ya que de todos modos no puede hacerlo más seguro.

Para el uso de registro , el cifrado asimétrico se parece a la herramienta correcta. El cifrado asimétrico adecuado ya incluye relleno aleatorio (para evitar una búsqueda exhaustiva de los datos en sí, en realidad solo hay cuatro billones de direcciones IPv4). RSA-4096 es un exceso excesivo, sin embargo; 1024 bits serían suficientes para obtener información de bajo valor como las direcciones IP (consulte esta respuesta para obtener más información). Una vez más, RSA-1024 significa que cada dirección IP encriptada usará 128 bytes, y es posible que desee optimizar las cosas un poco, para ahorrar espacio.

Podrías, por ejemplo, hacer un cifrado híbrido con Curva elíptica Diffie-Hellman : para cifre una dirección IPv4, haga un ECDH con respecto a una clave pública (el mismo principio que su clave RSA: el administrador solo guarda la clave privada) y use el secreto compartido resultante para cifrar la dirección IPv4. Use Formato que conserva el cifrado para cifrar la dirección IPv4 en cuatro bytes (por ejemplo, con la combinación Thorp o, más simple, con un cifrado de flujo inicializado con la clave DH). Para la "seguridad de 128 bits", necesita una curva elíptica de 256 bits, y una clave pública ECDH puede codificarse a través de 32 bytes. Junto con la dirección IP encriptada, eso es 36 bytes por dirección.

Para reducirlo aún más, aplique el consejo de @D.W.: haga lo mismo con ECDH una vez que se inicie el servidor y mutualice el uso de la clave compartida. Tendría una tabla de claves públicas ECDH, que crece lentamente (una nueva entrada por reinicio), y cada dirección IP cifrada solo haría referencia a la clave que se usará (un campo de 32 bits sería suficiente). Tenga en cuenta, sin embargo, que en este caso, debe tener cuidado de aleatorizar el cifrado simétrico de las direcciones IP. Por ejemplo, rellene la dirección IP (4 bytes) con 12 bytes de forma aleatoria y cifre los 16 bytes como un bloque con AES . Junto con la referencia de la clave pública, este menor costo disminuye a aproximadamente 20 bytes por IP. Sin la aleatorización, un atacante podría deducir qué direcciones IP se repiten a través de los registros. Dado que este esquema reutiliza la clave simétrica, el cifrado también debe hacerse con más cuidado (por ejemplo, un cifrado de flujo como RC4 se convertiría en una muy mala idea).

Sobre el rendimiento de la CPU: como @ D.W. señala, esto no es un problema. Con ECDH, usted está por debajo de 0.1ms por dirección IP. El cifrado RSA estará incluso por debajo de dichos costos. Es por eso que me concentro en el espacio del rendimiento anterior, no en la CPU.

    
respondido por el Thomas Pornin 03.09.2012 - 18:59
fuente
1

Buena pregunta!

Hay 256 ^ 4 direcciones IPv4 posibles. Si usa un algoritmo que no produce colisiones (una ip produce un hash único), puede relacionarlo con el principio de casillero donde tiene la misma cantidad o más casillas (hashes) que palomas (IP). Normalmente, tendrías > 256 ^ 4 casilleros para almacenar las direcciones IP cifradas con un algoritmo hash que no produce colisiones.

Un atacante podría realizar fácilmente una búsqueda de fuerza bruta en su base de datos para ver qué hash que corresponde a cada dirección IP, debido al hecho de que un hash uno a uno sería fácil de encontrar con la baja entropía de 256 ^ 4 Posibles direcciones IP (incluso con múltiples iteraciones de algoritmos). Si no es necesario poder hacer coincidir una IP con la base de datos con una precisión del 100%, un enfoque podría ser reducir la cantidad de casilleros. Esto también introducirá colisiones de hash en el algoritmo elegido.

Por lo tanto, si utiliza un tamaño de hash de, por ejemplo, 256 ^ 3 (3 bytes), cada dirección IP tendrá 256 posibles colisiones.

No mencionó la posibilidad de colisiones falsas en su lista de restricciones, por lo que no sé si esto le fue útil.

Otro enfoque que debe considerar es el uso del cifrado completo del disco con el uso del servidor de autenticación remota. Creo que encontrará una solución que utilice el cifrado de disco previo al arranque, como PBConnex suficiente si usa Servidor de windows. Actualmente no recuerdo el nombre de la solución de Linux, pero sé que hay al menos una.

    
respondido por el Dog eat cat world 20.04.2012 - 18:55
fuente
0

No es una buena pregunta !!!!!!!

Parece que su deseo de asegurar el sistema está impulsando el diseño aquí en lugar de equilibrar la funcionalidad, el rendimiento, la capacidad y la seguridad.

Encriptar datos en bases de datos es una lata de gusanos. La forma de cifrar depende de cómo desea acceder a los datos. Si solo desea encontrar coincidencias explícitas, seguro, puede cifrar fuera de la base de datos y escribir los datos cifrados en la base de datos. También puede redactar consultas basadas en predicados encriptados. Pero las cosas comienzan a complicarse cuando se intenta encontrar un valor en un rango, ya sea un rango en la consulta o un rango en el registro de la base de datos.

  

También sería útil verificar contra / 24 comodines (por ejemplo, 10.20.30. *)

Esto implica que desea utilizar rangos en su base de datos. Describir los datos en términos de notación CIDR significa que no puede usar índices para encontrar los datos (a menos que use una máscara de red fija). La forma correcta de resolver el problema es usar INET_ATON (from_address) e INETATON (to_address) en la base de datos; existen varias buenas razones para hacerlo, incluso si solo desea almacenar una dirección específica por registro en su base de datos. Pero para encontrar registros de manera eficiente, debe asignar estos (valores unidimensionales) a un espacio bidimensional y usar indexación geoespacial para buscar registros.

Entonces, ¿dónde deja eso su requisito de cifrado?

  

No necesita ser resistente a los atacantes que pueden ejecutar consultas

     

Debe ser resistente a los atacantes que tienen acceso a los archivos en el disco

... fácil, encripta el sistema de archivos en el que se encuentra la base de datos.

  

No se puede ingresar ninguna forma de clave o contraseña en el inicio del sistema

Eso es mucho más difícil

La respuesta aceptada aquí es muy escasa en detalles, y es posible que pueda mantener la clave en el shmop de PHP, pero debe llenar los datos allí cuando se inicia el servidor de aplicaciones.

Hay algo de discusión sobre solución potencial aquí al problema de mantener los ekys de cifrado de almacenamiento.

    
respondido por el symcbean 22.02.2018 - 13:19
fuente

Lea otras preguntas en las etiquetas