Tengo un proceso de pago para un carrito de compras que actualmente almacena datos de tarjetas de crédito en la sesión para recuperarlos una vez que el usuario finaliza la compra. El proceso de compra está configurado de tal manera que el usuario ingresa la tarjeta de crédito, ve una página de confirmación y luego finaliza el pedido. Las acciones de confirmación y finalización son las dos únicas acciones que necesitan acceso a los datos de la tarjeta de crédito y para estar seguro de que todas las demás acciones deben descartarlo.ASP.NET MVC - Almacenamiento temporal seguro de datos de tarjetas de crédito
A falta de hacer la reflexión en un controlador base para comprobar la acción actual que está llamando el usuario, no puedo pensar en una forma elegante de descartar los datos en las solicitudes no permitidas. Además, si el usuario no realiza otra solicitud después de ingresar los datos, permanecerá en la sesión hasta que vuelva al sitio web, siempre que eso suceda. Una sugerencia que me ofrecieron fue encriptar los datos en un campo oculto y confiar en el boleto SSL para evitar el almacenamiento en caché del marcado. Parece un enfoque bastante seguro, pero no me gusta la idea de cifrar o no los datos de la tarjeta de crédito en una ubicación accesible para el usuario. El almacenamiento en la base de datos se ha eliminado porque el cliente no desea que se guarden los datos de la tarjeta de crédito.
¿Cuál es el enfoque ideal para persistir temporalmente datos confidenciales como la información de la tarjeta de crédito en más de una solicitud de página?
Tal vez alguien me puede decir si este es un enfoque suficiente. He configurado mi Carrito de Compras que está almacenado en la sesión para tener un Guid único generado cada vez que se actualiza el objeto y ese Guid se utiliza como clave para cifrar y descifrar los datos de la tarjeta de crédito que estoy serializando con el Rijndael algorithm. Los datos de la tarjeta encriptada se pasan luego al usuario en un campo oculto y se deserializa luego de hacer clic en finalizar. El resultado final es una cadena muy parecido a éste:
VREZ%2bWRPsfxhNuOMVUBnWpE%2f0AaX4hPgppO4hHpCvvwt%2fMQu0hxqA%2fCJO%2faOEi%2bX3n9%2fP923mVestb7r8%2bjkSVZDVccd2AJzCr6ak7bbZg8%3d
public static string EncryptQueryString(object queryString, Guid encryptionKey)
{
try
{
byte[] key = Encoding.UTF8.GetBytes(ShortGuid.Encode(encryptionKey).Truncate(16));//must be 16 chars
var rijndael = new RijndaelManaged
{
BlockSize = 128,
IV = key,
KeySize = 128,
Key = key
};
ICryptoTransform transform = rijndael.CreateEncryptor();
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
{
byte[] buffer = Encoding.UTF8.GetBytes(queryString.ToString());
cs.Write(buffer, 0, buffer.Length);
cs.FlushFinalBlock();
cs.Close();
}
ms.Close();
return HttpUtility.UrlEncode(Convert.ToBase64String(ms.ToArray()));
}
}
catch
{
return null;
}
}
Acerca de su actualización: encriptar la información de la tarjeta no es el obstáculo, es difícil garantizar que todas las piezas de la solución sean seguras. Por ejemplo, ¿dónde está almacenando el GUID utilizado como clave? ¿Alguien más tiene acceso al servidor que genera los GUID? (Esto puede hacer posible que alguien adivine los GUID). ¿Está utilizando el mismo GUID por sesión o por duración de la aplicación? – meklarian
Además, el bloque catch {} da un poco de miedo. ¿No sería mejor devolver una cadena vacía allí? – meklarian
Buen punto en ToString() meklarian. Copié eso de otro lado sin mirar demasiado de cerca. El Guid se genera una vez por usuario por sesión, por lo que creo que conseguir un Guid del usuario sería bastante complicado. –