Necesito almacenar datos encriptados en una tabla y que se puedan desencriptar. Hay muchas soluciones para hacer esto, desde usar al propio MySQL para esto con ENCRYPT/DECRYPT, hasta hacerlo desde python. El problema en todas las situaciones es que tengo que disponer de la clave para cifrar/descifrar el dato por lo que si lo hardcodeo en el código y alguien logra acceder por shell a mi servidor (es decir, que me lo hackean), tengo los datos vendidos.
Tengamos por ejemplo que queremos subir un fichero, pero queremos almacenarlo cifrado sin que desde el servidor pueda desencriptarlo. Para evitar el problema de que me comprometan el servidor, se me ocurrió cifrar el fichero desde el navegador con una función en javascript que me quedó bastante bien, en la que el usuario pusiese la pass para cifrar y descifrar de tal modo que los datos llegasen cifrados. Esto es muy seguro pero cada vez que el usuario necesita obtener el fichero, el usuario se ve obligado a dar el pass, algo bastante incómodo.
Otro caso es por ejemplo almacenar los datos de usuario y contraseña de un servidor de correo remoto. En este caso os pongo de ejemplo un trozo de código de un proyecto que tengo en el que almaceno user y pass de la cuenta de un usuario ajeno a mi servicio en un servidor de correo ajeno también.
# -*- coding: utf-8 -*-
from gluon import *
from gluon.dal import SQLCustomType
import logging, datetime, m2secret, hashlib
from applications.ejemplo.modules.settings import Settings
logger = logging.getLogger(" >>>> modules/adminsettings >>>> tuvozlegal: ")
logger.setLevel(logging.DEBUG)
class Cifrar:
def __init__(self):
self.key= hashlib.sha256("password").digest()
def __call__(self,value):
secret = m2secret.Secret()
secret.encrypt(value, self.key)
return secret.serialize()
def formatter(self,value):
secret = m2secret.Secret()
secret.deserialize(value)
return (secret.decrypt(self.key), None)
class Adminsettings(object):
def __init__(self, db):
self.db=db
def define_tables(self):
config=Settings()
data= Cifrar()
cryp = SQLCustomType(type ='text', native ='longtext', encoder =(lambda x: data(x)), decoder = (lambda x: data.formatter(x)[0] ))
self.db.define_table('adminsettings',
Field('mailserver', 'string'),
Field('username', 'string', length=128, requires=IS_NOT_EMPTY(error_message="No puede estar vacío")),
Field('password', type=cryp, length=256, readable=False, label='Password'),
Field('emailfrom', 'string', length=128, requires=IS_EMAIL(error_message="Formato de email incorrecto")),
Field('blogitems', 'integer', default=20),
Field('messageitems', 'integer', default=15),
Field('bloglistitems', 'integer', default=15),
Field('useritems', 'integer', default=15),
Field('subscriptionitems', 'integer', default=15),
migrate=config.settings['migrate'])
Si veis la clase Cifrar en la línea "self.key= hashlib.sha256("password").digest()" está el password hardcoded para poder cifrar y descifrar la pass del servicio remoto en la base de datos. Aunque el dato está almacenado de un modo seguro, si me logueo en el server y tengo acceso al código fuente de la aplicación se puede ver el password que sirve para descifrar el dato :-( así que sigo vendido en caso de intrusión.
Existe alguna estrategia para solventar esto?
Un saludo