php|January 12, 2022|2 min read

Paypal Payment Issue While Validating Payment - Access Denied

TL;DR

The PayPal 'Access Denied' error on payment validation occurs when the validation endpoint URL changes; update the cgi-bin/webscr URL to the current PayPal endpoint.

Paypal Payment Issue While Validating Payment - Access Denied

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.

Related Posts

How to install Mongo DB Driver for Php 7.x

How to install Mongo DB Driver for Php 7.x

The simplest way to install driver for php is using pecl. When I tried to run…

How to get all image tags from an html - php code

How to get all image tags from an html - php code

I wanted to fetch all image tags from a big html, and wanted to perform some…

Drupal 7 - Code for Exporting all your content nodes in json files

Drupal 7 - Code for Exporting all your content nodes in json files

Introduction When I migrated all of my drupal-7 website to drupal-8, I wrote…

Drupal: How to block a user by email programatically

Drupal: How to block a user by email programatically

Many times, while administering your drupal website, you must have encountered…

php55w-common conflicts with php-common-5.* | Php issues while installing libraries

php55w-common conflicts with php-common-5.* | Php issues while installing libraries

I was trying to install mongo extension with pecl. It gave me error: Then, I…

Drupal Helpful codes for database queries

Drupal Helpful codes for database queries

Being a drupal user from last around 5 years, I used to know small codes for…

Latest Posts

Claude Code Skills — Build a Better Engineering Workflow with AI-Powered Code Reviews, Security Scans, and More

Claude Code Skills — Build a Better Engineering Workflow with AI-Powered Code Reviews, Security Scans, and More

Most developers use Claude Code like a search engine — ask a question, get an…

Building an AI Voicebot for Visitor Check-In — A Practical Guide to Handling the Messy Parts

Building an AI Voicebot for Visitor Check-In — A Practical Guide to Handling the Messy Parts

Every office lobby has the same problem: a visitor walks in, nobody’s at the…

Server Security Best Practices — Complete Hardening Guide for Production Systems

Server Security Best Practices — Complete Hardening Guide for Production Systems

Every breach post-mortem tells the same story: an unpatched service, a…

Staff Engineer Study Plan for MAANG Interviews — The Complete 12-Week Roadmap

Staff Engineer Study Plan for MAANG Interviews — The Complete 12-Week Roadmap

If you’re a Senior Engineer (L5) preparing for Staff (L6+) roles at MAANG…

XSS and CSRF Explained — The Complete Guide with Real Attack Examples and Defenses

XSS and CSRF Explained — The Complete Guide with Real Attack Examples and Defenses

XSS and CSRF have been in the OWASP Top 10 for over a decade. They’re among the…

OWASP Top 10 (2021) — Every Vulnerability Explained with Code

OWASP Top 10 (2021) — Every Vulnerability Explained with Code

The OWASP Top 10 is the industry standard for web application security risks. If…