miércoles, 14 de agosto de 2019

Encriptación de columnas en PostgreSQL

PostgreSQL es una base de datos relacional ideal para diferentes escenarios, con una larga historia desde 1982 en el corazón de la Universidad de Berkeley hasta nuestros días. Entre sus características más notables destacan su alta concurrencia, la variedad de tipos de datos nativos, tratamiento de datos geométricos, soporte a transacciones distribuidas, drivers para multitud de lenguajes de programación, alta seguridad o su disponibilidad en entornos cloud como Azure o AWS.

Dentro de la materia de Seguridad, encontramos artefactos para implementar la encriptación mediante diferentes opciones (consultar la documentación oficial). Una de estas formas de encriptación la encontramos a nivel de columna, la cual podemos implementar a través de una extensión llamada pgcrypto. Para usar esta extensión, debemos crearla dentro de la base de datos en uso mediante el comando:

CREATE EXTENSION pgcrypto;


Ahora tenemos a nuestra disposición nuevas funciones para incorporar en el lenguaje SQL, a nivel de columna.

La primera función se llama PGP_SYM_ENCRYPT(), y permite encriptar un texto dado, mediante al algoritmo especificado. La siguiente sintaxis encripta mi nombre mediante el algoritmo AES-KEY:

PGP_SYM_ENCRYPT('Rafael','AES_KEY')

La segunda función se llama PGP_SYM_DECRYPT(), y desencripta la columna encriptada mediante el algoritmo especificado:

PGP_SYM_DECRYPT(nombre_columna::bytea, 'AES_KEY')


Ejemplo

Vamos a poner en práctica lo anterior. En primer lugar vamos a crear una tabla de usuarios, en donde almacenaremos los nombres de usuarios y su contraseña, la cual vamos a encriptar para evitar robo de contraseñas:

CREATE TABLE usuarios(nombre VARCHAR(50), password VARCHAR(255));

INSERT INTO usuarios (nombre, password) VALUES ('Rafael', PGP_SYM_ENCRYPT('mypassword','AES_KEY'));

Si se lista la información, veremos que la contraseña está encriptada:

SELECT nombre, password FROM usuarios;

Para ver los datos desencriptados, utilizaremos la siguiente sentencia:

SELECT nombre, pgp_sym_decrypt(password::bytea,'AES_KEY') FROM usuarios;

La siguiente sentencia cambia la contraseña, encriptando la misma:

UPDATE usuarios SET password=(PGP_SYM_ENCRYPT('newpassword', 'AES_KEY'));

Podemos hacer una búsqueda comparando el valor en plano con el valor desencriptado de la columna encriptada. En nuestro ejemplo, cuando hacemos un login, hemos de comparar el nombre y la contraseña. La siguiente sentencia resuelve el problema:

SELECT COUNT(*) AS coincidencias FROM usuarios WHERE nombre = 'Rafael' AND PGP_SYM_DECRYPT(password::bytea, 'AES_KEY') = 'newpassword';


Ver también