php - Almacenar números de tarjeta de crédito en SESSION-¿formas de evitarlo?
mysql credit-card (13)
Estoy al tanto del cumplimiento de PCI, por lo que no es necesario que guarde los números CC (y especialmente los CVV nums) en la base de datos de nuestra compañía durante el proceso de pago.
Sin embargo, quiero estar lo más seguro posible al manejar información delicada del consumidor y tengo curiosidad por cómo pasar los números CC de una página a otra SIN usar las variables SESIÓN si es posible.
Mi sitio está construido de esta manera:
- Paso 1) recopilar información de la tarjeta de crédito del cliente: cuando el cliente ingresa el envío, la información se ejecuta primero a través de la validación de JS, luego se ejecuta a través de la validación de PHP; si pasa, pasa al paso 2.
- Paso 2) La información se muestra en una página de revisión para que el cliente se asegure de que se muestren los detalles de su próxima transacción. Solo los primeros 6 y los últimos 4 CC se muestran en esta página, pero el tipo de tarjeta y la fecha de expiración se muestran completamente. Si hace clic en continuar,
- Paso 3) La información se envía a otra página php que ejecuta una última validación, envía información a través de la pasarela de pago seguro y la cadena se devuelve con detalles.
- Paso 4) Si todo está bien y bien, la información del consumidor (personal, no CC) se almacena en DB y se redirige a una página de finalización. Si algo es malo, se le informa y se le pide que vuelva a visitar la página de procesamiento de CC para volver a intentarlo (máximo de 3 veces).
¿Alguna sugerencia?
EDITAR
He recibido una respuesta realmente buena sobre esta pregunta; la mayoría parece estar de acuerdo en lo siguiente:
- tomar variables POST después de ejecutar la validación
- encriptación de ccnum y cvv (sin embargo, no estoy seguro de poder almacenar cvv en DB)
- Almacenamiento en DB temporal
- Acceda a la base de datos inmediatamente después de que la página de "revisión" esté OK.
- descifrar detalles de DB
- enviar información al procesador
- recibir respuesta
- terminar DB
Creo que esto tiene sentido en general. ¿Alguien tiene un buen método para el cifrado / descifrado junto con la mejor manera de crear información de temp DB que se elimina automáticamente en una llamada posterior?
Estoy programando en PHP y MySQL DB
EDIT # 2
Me encontré con Packet General, que parece una solución ideal, pero REALMENTE no quiero pagar otra licencia de software para lograr este objetivo. http://www.packetgeneral.com/pcigeneralformysql.html
EDIT # 3 - Código de muestra
Ahora publiqué un código de ejemplo que integé tratando de entender el cifrado / descifrado / clave y el almacenamiento mencionados en esta publicación. Afortunadamente, los colaboradores que ya son útiles pueden validar y otros pueden usar funcionalidades similares. En aras de la longitud, no entraré en los métodos de validación utilizados para el propio CC num.
Entrada de formulario
<form action="<?php $_SERVER[''PHP_SELF'']; ?>" method="POST">
<input type="text" name="CC" />
<input type="text" name="CVV" />
<input type="text" name="CardType" />
<input type="text" name="NameOnCard" />
<input type="submit" name="submit" value="submit" />
</form>
PHP cifrar y almacenar datos
<?php
$ivs = mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivs,MCRYPT_RAND);
$key = "1234"; //not sure what best way to generate this is!
$_SESSION[''key''] = $key;
$ccnum = $_POST[''CC''];
$cvv = $_POST[''CVV''];
$cctype = $_POST[''CardType''];
$ccname = $_POST[''NameOnCard''];
$enc_cc = mcrypt_encrypt(MCRYPT_DES, $key, $ccnum, MCRYPT_MODE_CBC, $iv);
$enc_cvv = mcrypt_encrypt(MCRYPT_DES, $key, $cvv, MCRYPT_MODE_CBC, $iv);
$enc_cctype = mcrypt_encrypt(MCRYPT_DES, $key, $cctype, MCRYPT_MODE_CBC, $iv);
$enc_ccname = mcrypt_encrypt(MCRYPT_DES, $key, $ccname, MCRYPT_MODE_CBC, $iv);
//if we want to change BIN info to HEXIDECIMAL
// bin2hex($enc_cc)
$conn = mysql_connect("localhost", "username", "password");
mysql_select_db("DBName",$conn);
$enc_cc = mysql_real_escape_string($enc_cc);
$enc_cvv = mysql_real_escape_string($enc_cvv);
$enc_cctype = mysql_real_escape_string($enc_cctype);
$enc_ccname = mysql_real_escape_string($enc_ccname);
$sql = "INSERT INTO tablename VALUES (''$enc_cc'', ''$enc_cvv'', ''$enc_cctype'', ''$enc_ccname'');
$result = mysql_query($sql, $conn) or die(mysql_error());
mysql_close($conn);
Header ("Location: review_page.php");
?>
PHP descifrar datos y enviarlos a la puerta de enlace
$conn = mysql_connect("localhost", "username", "password");
mysql_select_db("DBName",$conn);
$result = mysql_query("SELECT * FROM tablename");
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION[''key''], $enc_ccnum, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION[''key''], $enc_cvv, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION[''key''], $enc_cctype, MCRYPT_MODE_CBC, $iv);
echo mcrypt_decrypt (MCRYPT_DES, $_SESSION[''key''], $enc_ccname, MCRYPT_MODE_CBC, $iv);
mysql_close($con);
?>
luego proceda a tomar los datos que acaba de enviar en la cadena y utilizar en el envío de Gateway. ¿Parece correcto?
¿Hay alguna razón por la cual no puede omitir el paso de confirmación y simplemente enviar la transacción de inmediato?
No veo por qué mantenerlo en una base de datos es más seguro que mantenerlo en una variable de sesión: el compromiso del servidor aún dará el número de la tarjeta de crédito, pero si lo mantiene en la sesión es mucho menos probable que se escriba en él disco. Puede encriptarlo si lo desea, pero la utilidad de esto es dudosa (aún se cambiará al disco). Agregar otra máquina para hacer almacenamiento encriptado tampoco ayuda, ya que la máquina comprometida puede pedirle a la otra que descifre.
EDIT: solo pensé en esto:
- Genera una clave aleatoria de 128 bits. Guarde esto en la sesión.
- Encripta los datos con la clave. Enviarlo al cliente en un <input type = "hidden">
- En la confirmación, descifrar los datos y enviar la transacción.
Un atacante debe comprometer tanto al cliente como al servidor para obtener el número de la tarjeta de crédito (tal atacante probablemente ya tenga el número de todos modos). Un compromiso de servidor en línea aún obtendrá los números de tarjeta de crédito de transacciones futuras, pero realmente no se puede detener eso.
EDITAR: Y olvidé los detalles. Para todos estos esquemas (no solo los míos), también necesitas un MAC para evitar los ataques de repetición (o Eve distrae a Alicia, modifica el carrito de la compra y la dirección de facturación, y presiona la página "confirmar" ...). En general, desea tener un MAC en todos los datos de transacción que tenga (CC, CVV, ID de transacción, importe de transacción, dirección de facturación ...).
Almacene los detalles de la tarjeta en cualquier medio de persistencia (base de datos, lo que sea), pero encripte el número de tarjeta con una clave única y aleatoria que almacene en la sesión. De esta forma, si la sesión se pierde, la clave también lo es, lo que le da tiempo suficiente para borrar los datos vencidos / abandonados.
También asegúrese de que sus sesiones estén protegidas del secuestro. Hay soluciones de hardware para esto, pero una forma simple en código es vincular el ID de la sesión a un hash del primer octeto de la IP más el agente de usuario. No es infalible, pero ayuda.
Editar : las claves para minimizar su riesgo es asegurarse de deshacerse de esa información lo antes posible. Inmediatamente después de la transacción, elimine el registro de la base de datos. También necesita un trabajo continuo (por ejemplo, cada 5 minutos) que borre cualquier registro anterior al tiempo de espera de la sesión (generalmente 20 minutos). Además, si está utilizando una base de datos para esta información muy temporal, asegúrese de que no se encuentre en un sistema de respaldo automático.
Una vez más, esta solución no es infalible y ni siquiera estoy 100% seguro de que cumpla con los requisitos de seguridad de CC. Sin embargo, debería requerir que un atacante tenga un control de tiempo de ejecución total de su entorno para descifrar activamente la información CC del cliente, y si una instantánea de su base de datos está comprometida (mucho más probable / común), solo un CC puede ser forzado a la vez, que es lo mejor que puedes esperar.
Así es como planeo hacerlo - todo a través de https usando ssl, por supuesto.
Paso 1. El usuario ingresa la información de CC y presiona el siguiente botón. La información de CC se guarda inmediatamente en la base de datos del procesador de CC, no en su propia base de datos o si se rompe el cumplimiento de PCI. El CC no se cobra realmente este paso. Pero debe recibir una identificación única del procesador que identifica la información CC. (almacena la identificación única en tu db si quieres)
Paso 2. En la página de confirmación, recupere la información CC del procesador CC usando el ID único que le dieron. Mi procesador solo me permitirá recuperar los últimos 4 números del CC de todos modos.
Paso 3. Después de que confirmen la compra y presionen el botón comprar ahora, carguen la tarjeta de crédito usando la identificación única.
Paso 4. Redirecciona a una página de agradecimiento que contiene la factura / recibo que solo tiene los últimos 4 dígitos del CC (por supuesto, no tienes que mostrar los últimos 4 del CC, pero creo que es bueno mostrar )
Considere modificar su proceso de pago para deshacerse de la necesidad de almacenar la información de la tarjeta de crédito.
Página 1: el usuario introduce información de orden de tarjeta de crédito, como dirección de envío y facturación
Página 2: El usuario verifica la información de la orden de la tarjeta de crédito, ingresa la información de la tarjeta de crédito y hace clic en "Pagar ahora" (o "Revisar orden" si quiere cambiar las cosas)
Paso 3: la información se envía a través de una solicitud $ _POST a una página SSL, que completa las comprobaciones en el servidor, envía los datos de la tarjeta de crédito al procesador y dirige al usuario a una página de éxito o error en función de la respuesta.
De esta forma evitará una bruma de problemas técnicos y problemas de cumplimiento. Almacenar los datos de la tarjeta de crédito en una base de datos o cookie, incluso durante un corto período de tiempo, incluso si están encriptados, significará que usted es responsable de un mayor nivel de cumplimiento de PCI. La única compensación es que no podrá mostrar una página de "orden de revisión" con detalles de la tarjeta de crédito. ¿Y cuán grande es la compensación, dado que su página de "orden de revisión" no puede mostrar el número completo de la tarjeta de crédito?
En algún momento más adelante en el procesamiento de pagos (última parte del paso 3), deberá encriptar el CC # (y el CVC) para poder enviarlo al procesador de pagos (supongo)
¿Por qué no hacer ese cifrado justo cuando recibe la información, junto a la ofuscación necesaria para la página de confirmación? (esta es la última parte del paso 1)
A partir de ahora, solo trabaje con estos datos encriptados u ofuscados, haciendo que la compañía CC sea la única que pueda descifrar la información completa.
Esto es para lo que es una base de datos. No estoy seguro acerca de las ramificaciones legales aquí (que varían según el país y la región), pero un enfoque sería encriptar el número CC y almacenarlo en la base de datos tan pronto como lo reciba del usuario. Es posible que desee almacenar los últimos 4 dígitos en un campo separado para que pueda mostrarlo al usuario cuando sea necesario. Cuando necesite interactuar con el procesador de la tarjeta en el servidor, recupere y descifre el número de tarjeta de su base de datos.
Hay otra manera, pero requiere Ajax. Sin almacenamiento de números de tarjeta de crédito Y una página de revisión.
Página 1: Formulario para capturar el envío, la facturación y la información de la tarjeta de crédito. Asegúrese de que el "cuerpo" de la página, incluido el formulario, se encuentre en una DIV con una identificación única que le permita referenciarlo con JavaScript.
Página 2: Un archivo en el servidor que aceptará una solicitud GET / POST con los campos del formulario y devolverá una página de "revisión" con el formato adecuado a su gusto.
Proceso de pago:
- Validar formulario
- Copie los campos relacionados con la tarjeta de crédito en variables globales de JavaScript.
- Pasa por los campos de formulario y crea una cadena de consulta / datos con los campos del formulario (excluyendo los campos relacionados con la tarjeta de crédito)
- Haga una solicitud de Ajax a la página "revisión", pasando la cadena de consulta de campo / valores de formulario con ella. Renderice en el servidor y vuelva a llamar a la función Ajax.
- Tome la página de revisión de HTML rendida devuelta por la solicitud de Ajax y reemplace el contenido de su contenedor "DIV" (reemplazando efectivamente el formulario y otros elementos con el HTML de revisión).
- Use JavaScript para copiar los datos de la tarjeta de crédito almacenados en las variables globales de JS en el lugar apropiado en la página de revisión. También puede copiar los datos de la tarjeta en campos de formularios ocultos para enviarlos cuando el usuario "complete" el pedido desde la página "revisión".
- El usuario envía el pedido desde la página de revisión al servidor, realiza la validación de la tarjeta con la puerta de enlace del procesador y luego coloca el pedido o regresa a la página de manejo de errores, sin haber almacenado los detalles de la tarjeta.
- Recomendaría que la función "realizar pedido" realice una solicitud HTTP completa (en lugar de Ajax) para volver a cargar el navegador con una página que ya no tenga los datos de la tarjeta almacenados en las variables globales JS.
Es un poco complicado, pero cuando se realiza correctamente, es 100% transparente para el usuario y le permite una sola transmisión de los datos de la tarjeta sin necesidad de asumir riesgos con el almacenamiento temporal de DB, etc.
No es necesario que las sesiones o la base de datos contengan la información.
Cada página es un formulario que publica los datos. En cada página posterior, las variables de publicación de la página anterior se agregan a los campos de formulario ocultos para que el siguiente envío de formulario publique nuevamente los datos. De esta forma, nunca se almacena nada, pero la información se transporta de página a página. Esto también obliga al usuario a completar el proceso de principio a fin sin intentar omitir los pasos.
Siempre que el formulario se envíe a través de HTTPS, los datos se cifran automáticamente y la carga de seguridad recae en su proveedor de certificados SSL.
Muchos sitios de comercio populares implementan esto. Por ejemplo, OSCommerce.
Parece que, de todos modos, al tocarlo, deberá proporcionar capacidades seguras de almacenamiento de números de tarjetas de crédito. Si el servidor está comprometido, en cualquier momento contendrá suficiente información para descifrar los números de tarjeta de crédito almacenados actualmente (es decir, claves y números encriptados). La solución potencial es usar un servidor interno que actúa como un servicio de "cifrado / descifrado" y nada más. De esta forma, comprometer una máquina no expone los números de las tarjetas de crédito.
Puede almacenar un hash de la tarjeta nr en sesión y el mismo hash y el número real y la identificación de la sesión del usuario en una base de datos. Luego, para cada página, puede verificar el hash y la información de la sesión para obtener la tarjeta nr.
Sé que usted mencionó que conoce el cumplimiento de PCI, pero usar cualquiera de los métodos ya descritos (por ejemplo, persistir el número de tarjeta en el disco en cualquier parte) será una falla de PCI y significará que tiene una pesadilla de dolores de cabeza por el cumplimiento. Si realmente insiste en persistir en el número de tarjeta en disco, entonces también podría obtener un auditor de PCI ahora para ayudarlo con el proceso y ofrecerle consejos. En última instancia, deberán validar que el método que ha tomado es el apropiado.
Como ejemplo, muchas de las respuestas aquí hablan sobre el uso de encriptación. Eso es lo fácil. No han hablado sobre la gestión de claves, que es significantly harder
Por lo tanto, creo que un mejor enfoque sería enviar los datos de la tarjeta a la pasarela de pago tan pronto como se recopilen. Una buena cantidad de pasarelas de pago le permitirán realizar una transacción de estilo ''solo de tienda'', que realizará la validación básica de los detalles de la tarjeta y almacenará el número de tarjeta en su servidor (que ya cumple con PCI) y le devolverá una identificación de token. Este método significa que usted NO almacena el número completo de la tarjeta / cvv2 en ningún lugar de sus servidores, y el cumplimiento de PCI se vuelve mucho más fácil.
Más adelante en el proceso de finalización de la compra, utiliza la identificación de token para enviar una autorización y una liquidación.
PCI le permite almacenar los primeros seis / últimos cuatro dígitos (y fecha de caducidad) del número de tarjeta en texto sin formato, para que pueda capturarlos con seguridad donde se sienta cómodo para que puedan volver a mostrarse justo antes del último paso.
Tiene razón, usar las sesiones es muy inseguro para almacenar datos confidenciales, hay formas de dividirse en sesiones con lo que se conoce como:
Secuestro de sesión
Fijación de sesión
La forma más segura que se me ocurre es que almacena la información en la base de datos (por tiempo temporal) y luego lee ese valor en la página donde lo necesita. Una vez que haya terminado de hacer todo, puede eliminarlo de nuevo.
Tenga en cuenta que:
- debe encriptarlo antes de guardarlo en la base de datos.
- tenga cuidado si está en hosting compartido
- asegúrese de eliminarlo una vez hecho esto
Puede encontrar this reflexivamente útil también :)
Usar tokenización Es totalmente compatible con PCI DSS.
Se puede encontrar más información aquí, https://www.pcisecuritystandards.org/documents/Tokenization_Guidelines_Info_Supplement.pdf