Paypal Payment Issue While Validating Payment - Access Denied

January 12, 2022

Introduction

I was using Paypal payment on one of my website, and suddenly lot of complaints started coming that their payment is not reflected. The exact error that was coming is:

Access Denied.

You don't have permission to access "/cgi-bin/webscr" on this server.

Why Validation

Let me expand the scenario a bit more. When user initiate a payment, I redirect user to the Paypal website. When user do the payment, it calls my website URL with the payment details.

It is a best practice from security perspective to validate this payment from Paypal.

Old Code for Validation in Php

$req = 'cmd=_notify-validate';
if (function_exists('get_magic_quotes_gpc')) {
    $get_magic_quotes_exists = TRUE;
}
else {
    $get_magic_quotes_exists = FALSE;
}

foreach ($postVars as $key => $value) {
    if ($get_magic_quotes_exists == TRUE) {
        $value = urlencode(stripslashes($value));
    }
    else {
        $value = urlencode($value);
    }
    $req .= "&$key=$value";
}

$url = 'https://www.paypal.com/cgi-bin/webscr';

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

if (!($res = curl_exec($ch))) {
  //invalid response
  curl_close($ch);
  return;
}
curl_close($ch);

if (strcmp($res, "VERIFIED") == 0) {
    $txn_type = strtoupper($_POST['txn_type']);

    switch ($txn_type) {
        // A subscriber has signed up for the service.
        case 'SUBSCR_SIGNUP':
            //handle_call1($res)
            break;

        case 'SUBSCR_CANCEL': // A subscriber cancelled a subscription.
        case 'SUBSCR_MODIFY': // A subscriber profile has been modified.
        case 'SUBSCR_FAILED': // A subscriber tried to pay for the service but things didn't work out.
        case 'SUBSCR_EOT': // A subscriber has reached the end of the subscription term.
            //do nothing
            break;

        // A subscriber has paid for the service.
        case 'SUBSCR_PAYMENT':
        case 'WEB_ACCEPT':
            //handle_call2($res);
            break;
    }
}
else {
    if (strcmp($res, "INVALID") == 0) {
        //Invalid response returned from Paypal
        return;
    }
}

Lets Focus on the main code:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));

Working Earlier

This solution worked for years. Suddenly, without any information Paypal did change something at their side. And, it took lot of time for me to figure out. As, it was not expected from Paypal to implement the breaking changes.

And, the error was:

Access Denied.

You don't have permission to access "/cgi-bin/webscr" on this server.

The Solution

Paypal started accepting a User-Agent header, with your company name. I think, the company name must have minimum 5 characters.

The code now becomes:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close', 'User-Agent: mycompany'));

And, it worked finally. Poor show Paypal. Hope it helps.


Similar Posts

Latest Posts