¿Una forma segura de almacenar detalles confidenciales de la API de los usuarios (local, almacenamiento o base de datos?

1

Estoy jugando con la idea de crear un sitio web para cryptocurrencies, donde un usuario pueda registrarse en mi sitio web, ingresar sus detalles de API para uno de los mercados de cambio que voy a admitir, lo que le permite comerciar en ese intercambio , pero usando mi interfaz web "más fácil de usar".

Mi objetivo principal es crear una interfaz más fácil de usar que la que ofrecen la mayoría de los sitios web de intercambio. No estoy conectado directamente a ninguna criptomoneda o billetera, todo lo que hago es usar la API de los mercados de intercambio existentes, transmitir la información a mi sitio web, donde tengo una interfaz más fácil de usar.

Dado que este es un tema muy delicado en lo que respecta a la seguridad, estoy tratando de averiguar cuál sería la mejor manera de almacenar los detalles de la API de los usuarios. En general, no me gusta la idea de almacenar los detalles de la API en mi servidor de base de datos, ni en mi servidor en general. La idea de tener mi sitio web pirateado y todos los detalles de la API que se exponen es aterrador. Por supuesto, cada sitio web de intercambio que admite API tiene su propia seguridad integrada, como sesiones de API con 2FA, restricciones de IP, generaciones semanales de nuevas claves secretas de API, límites de transacciones diarias a través de API y no permite retiros de billeteras a través de API. Pero aún se puede hacer daño si esos detalles de la API son robados.

Preferiría que hubiera una forma en la que no necesitara almacenar los detalles de la API en mi servidor, sino que el usuario los guarde localmente en su PC. De esa manera, él está a cargo de mantener seguros los detalles de la API.

Este pensamiento me llevó entonces a la idea de crear una aplicación de escritorio usando electron ( enlace ). De esa manera todavía puedo crear el sitio web de la manera que quiero, pero está envuelto en un electrón, por lo que siempre se ejecuta localmente. Antes de continuar con esta idea, me gustaría seguir investigando mi idea anterior de un sitio web regular, ya que prefiero tener mi sitio web basado en la nube, SaaS, para prevenir la piratería.

Así que me pregunto, al almacenar los detalles de la API de un usuario, sin guardarlos en el servidor, ¿qué otras opciones tendría? ¿Galletas? Probablemente no sea seguro. ¿Qué pasa con el almacenamiento local? enlace

¿Hay otras opciones o soy demasiado paranoico al respecto? ¿Se acepta generalmente almacenar información confidencial de la API en un servidor de base de datos junto con el resto de los usuarios?

    
pregunta Kevin M 16.11.2017 - 08:46
fuente

1 respuesta

2

¿Qué hay de almacenar los tokens de la API de una manera que ni siquiera usted pueda usarlos?

Cifre los tokens API con una clave derivada de la contraseña del usuario. Para evitar tener que enviar la contraseña al servidor en texto sin formato, puede usar un hash de la misma como clave, asegurándose de utilizar un salt diferente en el lado del cliente para el proceso normal de almacenamiento de la contraseña del servidor. Al iniciar sesión, los tokens se pueden extraer de la base de datos y descifrar. Si el usuario olvida su contraseña, los detalles de la API no se pueden recuperar de sus copias, pero eso está bien porque pueden obtenerlos y volver a ingresar desde los intercambios nuevamente.

Si adopta este enfoque, debe tomar medidas para asegurarse de que los tokens no estén paginados en su servidor. No tiene mucho sentido dedicar tanto esfuerzo para luego escribirlos en el disco de todos modos. También debe asegurarse de que se hayan vaciado de la memoria al cerrar sesión.

Otra alternativa sería obtener y usar las claves / tokens de API en la máquina del cliente, de esta manera nunca tendrá acceso a ellos en texto plano. Esto supone que las API de Exchange tienen políticas CORS que permiten que su aplicación las llame desde la máquina del cliente. Un ejemplo de derivación / uso clave utilizando la API de WebCrypto (más código completo aquí - enlace

var _algorithm = "AES-CBC";
var _key_size = 256;
var _pbkdf_iterations = 100;

// Do not change this once used in production
// If copying from StackExchange replace with a new random value for your app 
// or pass in a user specific value from the DB
var _defaultSalt = "af95a2b25229d227269a54fdec562d93";

// Derives a key from the given password.
// Salt is not required. If supplied should be a hex string.
function deriveKey(passphrase, salt)
{   
    if (typeof(salt) === 'undefined')
    {
        salt = _defaultSalt;
    }

    return passphrase == null || passphrase.length < 10 ?
        Promise.reject("Password must be at least 10 characters") :
        crypto.subtle.importKey(
            'raw',
            stringToUtf8ByteArray(passphrase),
            { name: 'PBKDF2'},
            false,
            ['deriveBits', 'deriveKey' ]
        ).then(function(passwordKey) {
            return crypto.subtle.deriveKey(
                {
                    "name": 'PBKDF2',
                    "salt": hexStringToByteArray(salt),
                    "iterations": _pbkdf_iterations,
                    "hash": 'SHA-256'
                },
                passwordKey,
                { "name": _algorithm, "length": _key_size },
                false, // Extractable is set to false so that underlying key details cannot be accessed.
                [ "encrypt", "decrypt" ]
            );
        });
}

function encryptData(keyObject, data)
{
    let iv = crypto.getRandomValues(new Uint8Array(16));

    return crypto.subtle.encrypt(
        {name: _algorithm, iv: iv},
        keyObject,
        data
    ).then(function(encryptedData) {
        return {
            iv:iv,
            data:encryptedData
        }
    });
}

function decryptData(keyObject, iv, encryptedData)
{   
    return crypto.subtle.decrypt(
        {name: _algorithm, iv: iv},
        keyObject,
        encryptedData
    );
}
    
respondido por el Hector 16.11.2017 - 09:35
fuente

Lea otras preguntas en las etiquetas