How to verify POST data comes from PayPal ?
I am working on a store that sells some products. The payment gateway is PayPal. Initially I set up a custom PayPal form and used the IPN responses to validate the data that is sent to me from PayPal.
Now my client has bought PayPal Advance Payment that uses PayPal PayFlow. The responses are not sent anymore through IPN (or are they?) instead they are returned by SILENT POST, basically when a transaction is perfomed on their end it is sent to a link of my choice and I process data through that link.
How do I validate the source of the POST data, so I know it is coming from PayPal and not a bad intentions user. I can not find any documentation on this. Also I want the same think when a users clicks "Cancel" button on paypal page and it is redirected to cancelation page on my website. I want that POST data source also verified.
Any thoughts on this ?
First solution than I found, also some PayPal support guy has mentioned something similar but he could not offer details as he said he is not an expert.
Basically you have to run a TRANSACTION of type INQUIRY with the received PNREF from SILENT POST, if the response returns ORIGRESULT equal to 0 then the transaction exists in PayPal database under your account.
I also send the SECURE TOKEN ID and SECURE TOKEN with the inquiry, I do not know if it helps or not, I saw this as a solution somewhere and I tried sending just TOKEN and TOKEN ID without ORIGID and sometimes it worked sometimes not.
On the developer reference from PayPal is specified that on a TRXTYPE=I (INQUIRY TRANSACTION) the ORIGID must be specified.
Code below:
//GET POST DATA FROM SILENT POST
$data = $_POST;
$result = $data['RESULT'];
$pnref = $data['PNREF'];
$secure_token = $data['SECURETOKEN'];
$secure_token_id = $data['SECURETOKENID'];
$fee_amount = $data['AMT'];
if(!isset($result) || $result != '0'){
//DO TRANSACTION FAILED OPERATIONS
exit;
}
//CHECK IF PNREF ID EXISTS ON PAYPAL
$post_data = "PARTNER=yourpartnerid"
."&VENDOR=your_vendor"
."&USER=your_user"
."&PWD=your_password"
."&SECURETOKENID=" . $secure_token_id
."&SECURETOKEN=" . $secure_token
."&ORIGID=" . $pnref
."&TRXTYPE=I"
."&VERBOSITY=HIGH";
$ch = curl_init('https://payflowpro.paypal.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$resp = curl_exec($ch);
$inquiry = array();
parse_str($resp, $inquiry);
//IF ORIGRESULT is 0 then PNREF/transaction exists.
if($inquiry['ORIGRESULT'] == '0' && $inquiry['RESPMSG'] == 'Approved'){ $validated = true; }
else{ $validated = false; }
if($result != 0 || $amount != 'your_correct_fee' || $validated == false){
// DO TRANSACTION NOT VALID OR HAS FAILED OPERATIONS
exit;
}
//DO TRANSACTION SUCCESSFULL OPERATIONS
The response from a INQUIRY looks this way:
RESULT=0&PNREF=ETHPC0BBF5FB&TRANSSTATE=8&ORIGRESULT=0&ORIGPNREF=ELFPB0E766F5&RESPMSG=Approved&AVSADDR=N&AVSZIP=N&ORIGPPREF=8GT035513B296200N&CORRELATIONID=97306f6456378&SETTLE_DATE=2014-07-09 14:11:36&TRANSTIME=2014-07-09 14:11:36&FIRSTNAME=John&LASTNAME=doe&AMT=0.0
Another way of doing it is checking the IP from which the SILENT POST is coming. I noticed all SILENT POST data comes from 173.0.81.65
$ip_address = $_SERVER['REMOTE_ADDR'];
if($ip_address != '173.0.81.65'){ exit; }
@Andrew Angel SILENT POST and NotifyURL is not the same thing. From the NotifyURL you can use IPN and data verification it is done very differently there because you receive different kind of post data string back.
I talked with PayPal support and they said NotifyURL and IPN is not available for PayPal Advanced Payments only for PayPal Payments Pro.
Indeed they both do the same function, but they are different things and source validation is done differently.
Hope this helps someone, waiting on opinions.