7

PayPal IPN sends a POST request with a variable number of fields to the notify URL, in order to confirm that the POST request is legit we need to resubmit the same request along with a additional cmd=_notify-validate field to PayPal, which then replies VERIFIED or INVALID.

My question is, why do we need to resend the request to PayPal? Wouldn't something like this suffice?

if (preg_match('~^(?:.+[.])?paypal[.]com$~i', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)
{
    // request came from PayPal, it's legit.
}

Iff we can trust the server to correctly resolve IPs, I assume we can trust all requests from PayPal, no?

Alix Axel
  • 151,645
  • 95
  • 393
  • 500

6 Answers6

7

This is the easiest way I have found to do it, also as per PayPal suggests. I use http_build_query() to construct the url from the post that was sent to the site from paypal. Paypal docs states that you should send this back for verification and that is what we do with file_get_contents. you will note that I use strstr to check if the word 'VERIFIED' is present and so we continue in the function, if not we return false...

$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;
Lobos
  • 559
  • 6
  • 5
  • Sure, but I don't think you've fully understood my question. – Alix Axel Jul 15 '11 at 17:32
  • This is the second time you've posted the same answer (the first was [here](http://stackoverflow.com/questions/4848227/validate-that-ipn-call-is-from-paypal/6710154#6710154)). It's fine to re-use the same example, but please consider tailoring your answer more specifically to each question. – Tim Post Jul 16 '11 at 01:35
  • 3
    Well if someone manages to spoof the IP address you are up shit creek - the reason I put the same answer here is cause people are finding this when searching out how to verify paypal IPN and the original post is Definitely not how to do it. – Lobos Jul 23 '11 at 20:11
6

PayPal is simply enforcing a higher standard of security for your own site/application's benefit.

IP spoofing can easily fool your example function, as relying on REMOTE_ADDRESS alone is quite prone to attack.

When you are working with financial transactions security is of great importance. If I can spoof an IPN request, I can trick your site/application into performing false transactions. By sending an additional request to a known and trusted location, we obtain a much higher standard of credential upon which to act. The entire original IPN request is sent in this confirmation so that PayPal may verify that all of the transaction details are in fact valid, thereby preventing a Man-in-the-Middle Attack whereby an attacker modifies details (say, changing a price or quantity) of an otherwise valid request as it is sent from PayPal to your server.

defines
  • 10,229
  • 4
  • 40
  • 56
  • I understand the PayPal position and I totally agree with the MITM vulnerability (although I've the impression that those kind of attacks are much more difficult to pull of in reality than in theory). What I don't understand is how one can spoof the REMOTE_ADDR - care to give a (practical) example? – Alix Axel May 18 '10 at 16:20
  • 1
    Edited 'as' not 'also', I meant that IP spoofing is a way to alter REMOTE_ADDRESS. You are right in that for most settings/targets, spoofing is probably out of the question (but not at wifi hot spots, college dorms, and other wide open subnets with a shared uplink). Once you've actually positioned yourself as a neighbor, altering the packets is rather trivial. – defines May 18 '10 at 19:19
5

I know this question is quite old, but:

The attacker does not even need to spoof his ip or perform any sort of MITM to pass your validation:

  1. He connects from his own machine with IP address x.y.z.t.
  2. Your server calls gethostbyaddr("x.y.z.t") which sends a dns query for the name t.z.y.x.in-addr.arpa.
  3. If x.y.z.t belongs to the attacker, chances are he controls (at least) the dns domain z.y.x.in-addr.arpa as well (since that contains his own ip). So he can return "paypal.com" in response to that query.
  4. Your server receives "paypal.com" from the attacker's dns server, and your validation check succeeds.

This attack is defeated by sending a request to paypal as recommended by Lobos.

tendays
  • 66
  • 1
  • 1
2

the whole thing falls apart if someone manages to alter the hosts file on the machine running your ipn listener;

  • bad person sends false payment notification

  • your compromised server sends duplicate to 'paypal.com' which is actually pointed to bad persons' machine

  • bad person replies VERIFIED, receives goods as if they had paid.

this isn't so much of a problem as if a person has r/w access to your hosts file they could probably just put the payment record into your database by hand, or do many other bits of damage.

just a thought.

lynks
  • 21
  • 1
1

Here is a reason to reply to the POST, from the IPN Guide:

Your listener must respond to each message, whether or not you intend to do anything with it. If you do not respond, PayPal assumes that the message was not received and resends the message. PayPal continues to resend the message periodically until your listener sends the correct message back, although the interval between resent messages increases each time.

IMPORTANT: PayPal expects to receive a response to an IPN message within 30 seconds.

Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • This is actually very misleading information from Paypal. What is required is that you respond to their POST request with an HTTP 200 and no data. You are not required to validate the data from Paypal in the way people are describing above. Its actually very important that the process follows as follows: 1) paypal post to your server 2) on a separate connection you post the data back to paypal 3) paypal responds with VERIFIED (or not) 4) you respond to paypals original POST with an empty 200. – Dom Sep 03 '15 at 16:35
0

Here is another solution - https://stackoverflow.com/a/4988281/2165415

(because your IPN page may need to check from where the call comes)

Community
  • 1
  • 1
T.Todua
  • 53,146
  • 19
  • 236
  • 237