2011-01-31 18 views
8

¿Cómo puedo validar que una solicitud POST de IPN de PayPal a mi notifyURL especificado proviene de PayPal?¿Validar que la llamada IPN es de PayPal?

No me refiero a comparar los datos con lo que envié anteriormente, pero ¿cómo puedo verificar que el servidor/dirección IP de donde proviene esta solicitud de PayPal es realmente válido?

+0

Los métodos enumerados aquí para validar que el IPN segundo palo vinieron de no son infalibles, y realmente no le hace mucho más seguro de lo que eres. Implemente las mejores prácticas recomendadas por PayPal. Si fueran inseguros, PayPal tendría problemas mayores, considerando que toda su marca se basa en la confianza de los usuarios. – Brad

Respuesta

16

El protocolo IPN consiste en tres pasos:

  1. PayPal envía el receptor de IPN un mensaje que le notifica del evento
  2. Su oyente envía el mensaje sin alteraciones de nuevo a PayPal; el mensaje debe contener los mismos campos en el mismo orden y ser codificado en la misma forma que el mensaje original
  3. PayPal envía una única palabra de nuevo, que es o bien verificadas en lo el mensaje originó con PayPal o no válido si hay alguna discrepancia con lo que era originalmente envió

https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro

+0

gracias, soy consciente de eso y lo estoy haciendo exactamente ... pero ¿cómo puedo estar doblemente seguro de que su PayPal que llama a mi oyente IPN? (el paso 1 que has copiado y pegado)? – siliconpi

+0

¿Hay alguna razón por la que deba serlo? Después de todo, todo el punto del proceso de 3 pasos descrito anteriormente es que es imposible que otra persona llame a su oyente de IPN y aún así obtenga una respuesta VERIFICADA ... – Amber

+0

No estoy 100% familiarizado con los ataques tipo "hombre en el medio", pero estoy pensando que una verificación más sólida de que la solicitud proviene de PayPal sería más prudente ... – siliconpi

1

Si no recuerdo mal, TH e PayPal usa una IP estática para sus llamadas IPN.

Por lo tanto, la verificación de la IP correcta debería funcionar.

alternativamente, puede hacer uso de gethostbyaddr o gethostbyname.

+0

+1 por recordarme que podría ser estático. Han pasado años desde que hice alguna programación de IPN. –

-1

Ésta es what I use:

if (preg_match('~^(?:.+[.])?paypal[.]com$~', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0) 
{ 
    // came from paypal.com (unless your server got r00ted) 
} 
+0

¿Qué pasa si compré el dominio blablablarandomstuffpaypal.com? ¿No coincidiría con esta expresión regular? un '[.]' antes de 'paypal' debería arreglar esto. – aularon

+0

@aularon: no coincidiría debido al '^'. –

+0

¡Completamente correcto! mi mal :) – aularon

11

Esta es la manera más fácil que he encontrado para hacerlo, también según sugiere PayPal. Utilizo http_build_query() para construir la url de la publicación que se envió al sitio desde PayPal. Los documentos de Paypal indican que debe enviar esto de vuelta para verificación y eso es lo que hacemos con file_get_contents. se dará cuenta de que yo uso strstr para comprobar si está presente la palabra 'verificado' y así continuamos en la función, si no volvemos falsa ...

$verify_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate&' . http_build_query($_POST); 

if(!strstr(file_get_contents($verify_url), 'VERIFIED')) return false; 
+1

En realidad, PayPal dice que debe ENVIARles el cuerpo: https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNIntro/ – acidtv

+0

¡Se requiere el encabezado HTTP User-Agent ahora! –

2

https://gist.github.com/mrded/a596b0d005e84bc27bad

function paypal_is_transaction_valid($data) { 
    $context = stream_context_create(array(
    'http' => array(
     'header' => "Content-type: application/x-www-form-urlencoded\r\n", 
     'method' => 'POST', 
     'content' => http_build_query($data), 
    ), 
)); 
    $content = file_get_contents('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, $context); 

    return (bool) strstr($content, 'VERIFIED'); 
} 
3

HTTP ¡Se requiere el agente de usuario de encabezado ahora!

$vrf = file_get_contents('https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, stream_context_create(array(
    'http' => array(
     'header' => "Content-type: application/x-www-form-urlencoded\r\nUser-Agent: MyAPP 1.0\r\n", 
     'method' => 'POST', 
     'content' => http_build_query($_POST) 
    ) 
))); 

if ($vrf == 'VERIFIED') { 
    // Check that the payment_status is Completed 
    // Check that txn_id has not been previously processed 
    // Check that receiver_email is your Primary PayPal email 
    // Check that payment_amount/payment_currency are correct 
    // process payment 
} 
+0

¡Genial! esto funcionó para mí –

+0

Si estoy probando con la caja de arena, ¿la URL sería www.sandbox.paypal.com para autenticarse con, o www.paypal.com? – Volomike

Cuestiones relacionadas