ssheduardo / sermepa

Clase para utilizar la pasarela de pagos redsys, sermepa.
MIT License
191 stars 59 forks source link

Bloquear IP para Ds_Response 2XX #75

Closed PyrusSp closed 3 years ago

PyrusSp commented 3 years ago

Buenas. Estaba haciendo algo muy parecido sólo que para C#. No obstante creo que resolvería igual. Según el manual, cuando en la notificación asíncrona se reciba un Ds_Response del tipo 2XX, hay que gestionar (almacenar en base de datos, por ejemplo) la IP del cliente porque es un código de posible fraude. En los parámetros enviados no se indica la IP, aunque sí es un dato que almacena el TPV como se puede ver al acceder al módulo de administración. Me he puesto en contacto con soporte y me indican que es algo que tengo que resolver yo en el código de la página de notificación, pero aunque les he dicho que a esa página se conecta el banco, no el cliente, porque estoy usando el modo de redirección, no me explican cómo. ¿Has podido gestionar este tipo de respuestas? ¿Habría que recurrir a almacenar la IP antes de hacer la redirección a la pasarela? Gracias y un saludo

ssheduardo commented 3 years ago

Hola, lo que puedes hacer es enviarlo como parámetro la IP tal vez codificada en el parámetro Ds_MerchantData y luego al retornar ese dato el Banco poder decodificarlo y guardarlo.

PyrusSp commented 3 years ago

Gracias. Buena idea. Lo probaré. Aunque no es muy lógico usar MerchantData para trasladar "ClientData" o "CustomerData".

ssheduardo commented 3 years ago

Ya pero es lo que se me ocurre de momento, ya me contaras que tal.

PyrusSp commented 3 years ago

Probado y funcionando. Le he pasado como parámetro _DS_MERCHANTMERCHANTDATA un JSON, resultado de serializar un objeto. Así se pueden pasar otros valores a parte de la IP, siempre y cuando no te pases de la longitud máxima (1024). Ojo, la respuesta _DsMerchantData devuelve el mismo JSON pero codificado. Hay que pasarle antes html_entity_decode() (creo que es lo que se usa para PHP) antes de analizar el objeto.

Muchas gracias @ssheduardo

ssheduardo commented 3 years ago

Genial, si puedes poner el ejemplo para que le sirva a otro genial.

PyrusSp commented 3 years ago

Sí, pero está en C#. Pay.cs

using System.Web.Script.Serialization;
using RedsysAPIPrj;

namespace TPV
{
    public class Pay
    {
        private RedsysAPI r;
        private readonly string ip = IPAddress.Parse(HttpContext.Current.Request.UserHostAddress).ToString();
        ...
        public string MerchantParameters {
            get {
                var jss = new JavaScriptSerializer();
                ...
                r.SetParameter("DS_MERCHANT_MERCHANTDATA", jss.Serialize(new MerchantData { IPClient = this.ip }));
                return r.createMerchantParameters();
            }
        }
   ...
    }
...
}

Response.cs

using Newtonsoft.Json;
using RedsysAPIPrj;

namespace TPV
{
    public class Response
    {
        public static (bool valid, string message) IsValidResponse() { ... }
        private static Dictionary<string, string> GetResponseParameters(string json) { ... }
        public static (bool valid, string message) SaveTransaction(SqlConnection sqlConnection) {
            var (valid, message) = IsValidResponse();
            if (!valid) { return (valid, message); }

            Dictionary<string, string> dParams = GetResponseParameters(message);
            int ds_response = int.Parse(dParams["Ds_Response"]);
            bool accepted = (ds_response < 100);
            bool blockIP = (200 <= ds_response && ds_response < 300);
            string decodeMerchantParameters = message;
            string commandText = @"...";
            int rowsAffected;
            using (sqlConnection)
            {
                using (SqlCommand cmd = new SqlCommand(commandText, sqlConnection)) {
                    cmd.CommandType = CommandType.Text;
                    ...
                    cmd.Parameters.AddWithValue("@ip", JsonConvert.DeserializeObject<MerchantData>(HttpUtility.HtmlDecode(dParams["Ds_MerchantData"])).IPClient);
                    cmd.Connection.Open();
                    rowsAffected = cmd.ExecuteNonQuery();
                    if (blockIP) {
                        cmd.CommandText = @"...";
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            ...
        }
    } 
}