Cómo buscar en una base de datos MySQL con campos encriptados

15

Supongamos que necesito encriptar ciertos campos de tabla de una base de datos MySQL . Además, necesito buscar algunos de esos campos que cifré.

¿Cómo se buscarían esos campos de todos modos?

Descifrar cada registro paso a paso no es una opción: supongamos que tengo varios miles de registros. Tomaría demasiado tiempo y espacio descifrar cada registro y verificar si cada registro coincide con la búsqueda.

ACTUALIZACIÓN 2012-09-07

Agregar más detalles al esquema de la base de datos estaría bien , ya que estoy a punto de implementar una nueva aplicación. Además, necesito extender las aplicaciones que actualmente se ejecutan en producción. Pero incluso para esas aplicaciones, agregar más detalles estaría bien.

ACTUALIZACIÓN 2012-09-08

El cifrado es el núcleo de esta pregunta.

Las restricciones de acceso, según lo propuesto por algunas respuestas, ya se aplican, pero no se ajustan al requisito formal de cifrar datos.

Este requisito formal no es el Estándar de seguridad de datos de la industria de tarjetas de pago [PCI].

SteAp
fuente

Respuestas:

11

Obviamente, no están destinados a ser vistos, por lo tanto, buscarlos sería problemático.

Un truco que he usado en el pasado es hacer un hash de los datos encriptados antes de encriptarlos, y almacenar el hash en una columna indexada. Por supuesto, esto solo funciona si está buscando todo el valor; los valores parciales no tendrán el mismo hash.

Probablemente podría extender esto haciendo un índice de "hash" de texto completo, si fuera necesario, pero podría complicarse realmente rápido.

APÉNDICE

Se ha sugerido que agregue una nota al pie de página a mi respuesta en un debate bastante largo en el chat sobre la vulnerabilidad a los ataques del diccionario, por lo que analizaré este posible riesgo de seguridad con el enfoque anterior.

Ataque de diccionario: Un ataque de diccionario es cuando alguien realiza un hash previo de una lista de valores conocidos y compara los hash con su columna hash en la base de datos. Si pueden encontrar una coincidencia, es probable que el valor conocido sea en realidad el valor hash (no es definitivo, porque no se garantiza que los hashes sean únicos). Por lo general, esto se mitiga al mezclar el valor con una "sal" aleatoria agregada o antepuesta para que el hash no coincida con el diccionario, pero la respuesta anterior no puede usar una sal porque pierde la capacidad de búsqueda.

Este ataque es peligroso cuando se trata de cosas como las contraseñas: si crea un diccionario de hashes de contraseñas populares, puede buscar rápidamente en la tabla ese valor de hash e identificar a un usuario que tiene dicha contraseña y extraer efectivamente las credenciales para robar la identidad de ese usuario .

Es menos peligroso para los artículos con un alto grado de cardinalidad, como los números de seguro social, los números de tarjeta de crédito, los GUID, etc. (pero existen diferentes riesgos [léase: legales] asociados con el almacenamiento de estos, por lo que no estoy dispuesto a aconsejarlos para almacenarlos )

La razón de esto es para que un ataque de diccionario funcione, debe haber creado previamente un diccionario de posibles valores y sus valores hash. Podría, en teoría, construir un diccionario de todos los números de seguro social posibles (mil millones de filas, suponiendo que se eliminen todas las permutaciones de formato; múltiples docenas de billones de entradas para tarjetas de crédito) ... pero ese no suele ser el objetivo de un ataque de diccionario, y básicamente se vuelve comparable a un ataque de fuerza bruta en el que investigas sistemáticamente cada valor.

También puede buscar un SSN o número de tarjeta de crédito específico , si está tratando de hacer coincidir un SSN con una persona. Nuevamente, generalmente no es el objetivo de un ataque de diccionario, pero es posible hacerlo, por lo que si esto es un riesgo que debe evitar, mi respuesta no es una buena solución para usted.

Entonces ahí lo tienes. Al igual que con todos los datos encriptados, generalmente están encriptados por alguna razón, así que tenga en cuenta sus datos y de qué está tratando de protegerlos.

Jeremy Holovacs
fuente
La discusión sobre esta respuesta se ha movido al chat .
Paul White reinstala a Monica
5

Es posible que desee echar un vistazo a CryptDB . Es una interfaz para MySQL y PostgreSQL que permite el almacenamiento transparente y la consulta de datos cifrados. Funciona cifrando y descifrando datos a medida que pasan entre la aplicación y la base de datos, reescribiendo consultas para operar en los datos cifrados. y ajustando dinámicamente el modo de cifrado de cada columna para exponer solo la cantidad de información necesaria para las consultas que utiliza la aplicación.

Los diversos métodos de cifrado utilizados por CryptDB incluyen:

  • RND , un esquema de cifrado seguro totalmente IND-CPA que no filtra información sobre los datos (excepto su presencia y, para tipos de longitud variable, longitud) pero solo permite el almacenamiento y la recuperación, sin consultas.

  • DET , una variante de RND que es determinista, de modo que dos valores idénticos (en la misma columna) se cifran en el mismo texto cifrado. Admite consultas de igualdad del formulario WHERE column = 'constant'.

  • OPE , un esquema de cifrado para preservar el orden que admite consultas de desigualdad como WHERE column > 'constant'.

  • HOM , un esquema de cifrado parcialmente homomórfico (Paillier) que permite agregar valores cifrados juntos multiplicando los textos cifrados. Admite SUM()consultas, adiciones e incrementos.

  • SEARCH , un esquema que admite búsquedas de palabras clave del formulario WHERE column LIKE '% word %'.

  • JOIN y OPE-JOIN , variantes de DET y OPE que permiten comparar valores en diferentes columnas entre sí. Soporta igualdad y rango se une respectivamente.

El verdadero poder de CryptDB es que adapta el método de cifrado de cada columna dinámicamente a las consultas que ve, de modo que los esquemas más lentos y / o menos seguros solo se utilizan para las columnas que los requieren. También hay varias otras características útiles, como el encadenamiento de claves de cifrado a las contraseñas de los usuarios.

Si está interesado, le recomendamos que eche un vistazo a los documentos vinculados desde el sitio web de CryptDB, en particular "CryptDB: Protección de la confidencialidad con procesamiento de consultas cifradas" de Popa, Redfield, Zeldovich y Balakrishnan ( SOSP 2011 ). Esos documentos también describen las diversas compensaciones de seguridad y rendimiento involucradas en el soporte de diferentes tipos de consultas con más detalle.

Ilmari Karonen
fuente
1
It works by encrypting and decrypting data as it passes between the application and the database: Sin duda, esto puede causar problemas si los datos que se buscan ya están en la base de datos (encriptados), pero obviamente la consulta que busca en la base de datos solo se pasa a CryptDB (¿y luego se encripta?). ¿No puedo entender cómo este método puede ser eficiente?
Martin
3

No entiendo por qué las respuestas actuales no han cuestionado los requisitos por completo, por lo que preguntaré y lo dejaré como respuesta.

¿Cuáles son las razones comerciales? ¿Qué datos necesitas encriptar y por qué? Si está buscando el cumplimiento de PCI, podría escribir un ensayo.

Preguntas sobre su requerimiento:

  • ¿Necesitará devolver un existe / no existe como resultado, o los datos reales?
  • ¿Requiere una capacidad LIKE '% OMG_SEKRIT%'?
  • ¿Quién no puede ver los datos y por qué?

La seguridad de RDBMS se realiza normalmente en función de los permisos impuestos por el usuario / rol. El RDBMS encripta los datos normalmente en el disco, pero no en los datos en columna, ya que eso no tiene ningún sentido para una aplicación diseñada para almacenar y recuperar datos de manera eficiente.

Restringir por usuario / rol / api. Cifrar en disco. Si está almacenando datos más importantes, me encantaría saber por qué está utilizando MySQL.

Philᵀᴹ
fuente
Principalmente, necesito encontrar existe / no existe y luego ubicar el registro específico. El soporte LIKE completo estaría bien. Pero me pregunto, que cualquier cosa más que la coincidencia de palabras será posible. El usuario autorizado puede ver datos. La aplicación descifra esos elementos, un usuario legítimo tiene derechos para ver. Los esquemas de base de permisos no son una opción.
SteAp
¿Cuál es el criterio para "datos más importantes"?
arcanine
2

Estoy investigando esto y encontré tu pregunta. Me estoy inclinando hacia el enfoque descrito en la sección 5.4 del documento "Técnicas prácticas para búsquedas en datos cifrados" http://www.cs.berkeley.edu/~dawnsong/papers/se.pdf

La esencia básica es crear un índice que contenga palabras clave cifradas que estén presentes en el documento de búsqueda cifrado. El truco es también encriptar las ubicaciones en el documento (o base de datos) donde esas palabras clave están presentes.

M. Scott Ford
fuente
1

Programáticamente, una solución eficiente es

  1. recupere TODOS los registros SOLO para el campo en el que está buscando con el ID de registro
  2. descifrarlos en una tabla temporal
  3. realizar la búsqueda contra esa tabla
  4. use los identificadores para recuperar los registros completos (todos los campos) que coinciden con los criterios de búsqueda
  5. descifrarlos y devolverlos al usuario

El punto es que 1 y 4 son conjuntos de datos significativamente más pequeños que recuperar y descifrar todos los campos de todos los registros al principio.

Espero que ayude.

Paul B. Hartzog
fuente
Las tablas temporales en texto sin formato son relativamente (es decir, muy) fáciles de capturar y leer, interrumpen el servidor en el momento correcto o simplemente copian la temp/carpeta y la bang, los valores de texto sin formato para toda la columna están ahí, esta no es una forma segura de operar
Martin
1

Esto es posible con la funcionalidad de búsqueda completa utilizando las funciones de cifrado interno de MYSQL.

Aquí hay un ejemplo:

!!! ESTOY USANDO EL CÓDIGO MYSQL () AQUÍ POR SIMPLICIDAD, MYSQL_ENCODE AHORA ES CONSIDERADO INSEGURA, ¡UTILICE UNA DE LAS OTRAS FUNCIONES MYSQL INTERNAS EN LUGAR!

UPDATE my_table
SET field=ENCODE('my_data', 'my_password')
WHERE ID=1;

SELECT DECODE(field, 'my_password') as field FROM my_table
WHERE field LIKE 'data';

Como sugiere el comentario anterior, NO use ENCODE (), use una de las otras funciones de cifrado. Solo estoy usando ENCODE en este ejemplo debido a su simplicidad

Si está haciendo esto dentro de una aplicación como php, puede hacerlo dentro de su puerta de enlace db o clases de repositorio almacenando una lista / matriz de las columnas cifradas de cada tabla dentro de su clase de puerta de enlace respectiva.

class UserGateway
{
    protected $encrypted_fields = array(
        'username',
        'email'
    );

    public function get($fields, ...)
    {
        foreach ($fields as $k => $field) {
            if (in_array($field, $fields)) {
                $fields[$k] = $this->decodeSelect($field);
            }
        }

        $sql = 'SELECT '.implode(',', $fields);

        //......
    }

    protected function decodeSelect($field)
    {
        return "DECODE($field, $pass) AS $field";
    }
}

Por supuesto, este es un código muy inseguro e inseguro que no debe usarse en producción sin una mejora significativa. Pero debe cumplir su propósito al dar la idea general.

Leigh Bicknell
fuente
-1

Suponiendo que está buscando en SQL y contra el valor completo y no parcial (por ejemplo, LIKE 'value%') ... al capturar los datos de búsqueda, cifre esos datos usando el mismo algoritmo utilizado cuando los datos se cifraron y búsquelos.

Por ejemplo:

Lo que hubiera sido:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'Value'

En cambio, podría verse así:

SELECT FieldA, FieldB 
FROM Table1 
WHERE FieldC = 'hsk&%67ghhks83'
WellyBoot
fuente
1
No. El cifrado decente funcionará con un valor de sal, por lo que si, por ejemplo, tiene una sal única para cada fila, entonces deberá usar cada sal en la cadena de búsqueda, esto se volverá complejo, costoso y bastante rápido
Martin