Подтвердить что ты не робот

Подтверждения IPN PayPal IPN с использованием процедур SSL: SSL3_READ_BYTES: сбой вызова подтверждения sslv3

Без изменений на нашей стороне и, возможно, связанных с POODLE/SSL3, наш API PayPal API для PPIPNMessage:: validate теперь терпит неудачу.

SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

Проверка и получение IPN в порядке (и мы никогда не поддерживали входящий SSL3), он просто терпит неудачу при подтверждении IPN (странно PayPal не пытается снова, даже если мы потерпели неудачу)

Запуск curl из той же командной строки сервера завершен

$ curl -iv https://ipnpb.paypal.com/cgi-bin/webscr
* About to connect() to ipnpb.paypal.com port 443 (#0)
*   Trying 173.0.88.8... connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using AES256-SHA
* Server certificate:
*    subject: 1.3.6.1.4.1.311.60.2.1.3=US; 1.3.6.1.4.1.311.60.2.1.2=Delaware; businessCategory=Private Organization; serialNumber=3014267; C=US; postalCode=95131-2021; ST=California; L=San Jose; street=2211 N 1st St; O=PayPal, Inc.; OU=PayPal Production; CN=ipnpb.paypa
*    start date: 2013-06-28 00:00:00 GMT
*    expire date: 2015-08-02 23:59:59 GMT
*    subjectAltName: ipnpb.paypal.com matched
*    issuer: C=US; O=VeriSign, Inc.; OU=VeriSign Trust Network; OU=Terms of use at https://www.verisign.com/rpa (c)06; CN=VeriSign Class 3 Extended Validation SSL CA
*    SSL certificate verify ok.
> GET /cgi-bin/webscr HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: ipnpb.paypal.com
> Accept: */*

Я заметил, что ssllabs.com показывает 1 из 4 IP-адресов, поддерживающих SSL3 на этой конечной точке.

4b9b3361

Ответ 2

У меня была та же проблема... Просто измените следующую строку на ipnlistener.php

от

curl_setopt($ch, CURLOPT_SSLVERSION, 3);

в

curl_setopt($ch, CURLOPT_SSLVERSION, 4);

ipnlistener.php

<?php
/**
* PayPal IPN Listener
*
* A class to listen for and handle Instant Payment Notifications (IPN) from
* the PayPal server.
*
* https://github.com/Quixotix/PHP-PayPal-IPN
*
* @package PHP-PayPal-IPN
* @author Micah Carrick
* @copyright (c) 2012 - Micah Carrick
* @version 2.1.0
*/
class IpnListener {

    /**
* If true, the recommended cURL PHP library is used to send the post back
* to PayPal. If flase then fsockopen() is used. Default true.
*
* @var boolean
*/
    public $use_curl = true;

    /**
* If true, explicitly sets cURL to use SSL version 3. Use this if cURL
* is compiled with GnuTLS SSL.
*
* @var boolean
*/
    public $force_ssl_v3 = true;

    /**
* If true, cURL will use the CURLOPT_FOLLOWLOCATION to follow any
* "Location: ..." headers in the response.
*
* @var boolean
*/
    public $follow_location = false;

    /**
* If true, an SSL secure connection (port 443) is used for the post back
* as recommended by PayPal. If false, a standard HTTP (port 80) connection
* is used. Default true.
*
* @var boolean
*/
    public $use_ssl = true;

    /**
* If true, the paypal sandbox URI www.sandbox.paypal.com is used for the
* post back. If false, the live URI www.paypal.com is used. Default false.
*
* @var boolean
*/
    public $use_sandbox = false;

    /**
* The amount of time, in seconds, to wait for the PayPal server to respond
* before timing out. Default 30 seconds.
*
* @var int
*/
    public $timeout = 30;

    private $post_data = array();
    private $post_uri = '';
    private $response_status = '';
    private $response = '';

    const PAYPAL_HOST = 'www.paypal.com';
    const SANDBOX_HOST = 'www.sandbox.paypal.com';

    /**
* Post Back Using cURL
*
* Sends the post back to PayPal using the cURL library. Called by
* the processIpn() method if the use_curl property is true. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* @param string The post data as a URL encoded string
*/
    protected function curlPost($encoded_data) {

        if ($this->use_ssl) {
            $uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
            $this->post_uri = $uri;
        } else {
            $uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr';
            $this->post_uri = $uri;
        }

        $ch = curl_init();

                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
                curl_setopt($ch, CURLOPT_CAINFO,
                 dirname(__FILE__)."/cert/api_cert_chain.crt");
        curl_setopt($ch, CURLOPT_URL, $uri);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_SSLVERSION, 4);

        if ($this->force_ssl_v3) {
            curl_setopt($ch, CURLOPT_SSLVERSION, 4); //Modified from 3 to 4
        }

        $this->response = curl_exec($ch);
        $this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));

        if ($this->response === false || $this->response_status == '0') {
            $errno = curl_errno($ch);
            $errstr = curl_error($ch);
            throw new Exception("cURL error: [$errno] $errstr");
        }
    }

    /**
* Post Back Using fsockopen()
*
* Sends the post back to PayPal using the fsockopen() function. Called by
* the processIpn() method if the use_curl property is false. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* @param string The post data as a URL encoded string
*/
    protected function fsockPost($encoded_data) {

        if ($this->use_ssl) {
            $uri = 'ssl://'.$this->getPaypalHost();
            $port = '443';
            $this->post_uri = $uri.'/cgi-bin/webscr';
        } else {
            $uri = $this->getPaypalHost(); // no "http://" in call to fsockopen()
            $port = '80';
            $this->post_uri = 'http://'.$uri.'/cgi-bin/webscr';
        }

        $fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);

        if (!$fp) {
            // fsockopen error
            throw new Exception("fsockopen error: [$errno] $errstr");
        }

        $header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
        $header .= "Host: ".$this->getPaypalHost()."\r\n";
        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $header .= "Content-Length: ".strlen($encoded_data)."\r\n";
        $header .= "Connection: Close\r\n\r\n";

        fputs($fp, $header.$encoded_data."\r\n\r\n");

        while(!feof($fp)) {
            if (empty($this->response)) {
                // extract HTTP status from first line
                $this->response .= $status = fgets($fp, 1024);
                $this->response_status = trim(substr($status, 9, 4));
            } else {
                $this->response .= fgets($fp, 1024);
            }
        }

        fclose($fp);
    }

    private function getPaypalHost() {
        if ($this->use_sandbox) return self::SANDBOX_HOST;
        else return self::PAYPAL_HOST;
    }

    /**
* Get POST URI
*
* Returns the URI that was used to send the post back to PayPal. This can
* be useful for troubleshooting connection problems. The default URI
* would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
*
* @return string
*/
    public function getPostUri() {
        return $this->post_uri;
    }

    /**
* Get Response
*
* Returns the entire response from PayPal as a string including all the
* HTTP headers.
*
* @return string
*/
    public function getResponse() {
        return $this->response;
    }

    /**
* Get Response Status
*
* Returns the HTTP response status code from PayPal. This should be "200"
* if the post back was successful.
*
* @return string
*/
    public function getResponseStatus() {
        return $this->response_status;
    }

    /**
* Get Text Report
*
* Returns a report of the IPN transaction in plain text format. This is
* useful in emails to order processors and system administrators. Override
* this method in your own class to customize the report.
*
* @return string
*/
    public function getTextReport() {

        $r = '';

        // date and POST url
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
        if ($this->use_curl) $r .= " (curl)\n";
        else $r .= " (fsockopen)\n";

        // HTTP Response
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "\n{$this->getResponse()}\n";

        // POST vars
        for ($i=0; $i<80; $i++) { $r .= '-'; }
        $r .= "\n";

        foreach ($this->post_data as $key => $value) {
            $r .= str_pad($key, 25)."$value\n";
        }
        $r .= "\n\n";

        return $r;
    }

    /**
* Process IPN
*
* Handles the IPN post back to PayPal and parsing the response. Call this
* method from your IPN listener script. Returns true if the response came
* back as "VERIFIED", false if the response came back "INVALID", and
* throws an exception if there is an error.
*
* @param array
*
* @return boolean
*/
    public function processIpn($post_data=null) {

        $encoded_data = 'cmd=_notify-validate';

        if ($post_data === null) {
            // use raw POST data
            if (!empty($_POST)) {
                $this->post_data = $_POST;
                $encoded_data .= '&'.file_get_contents('php://input');
            } else {
                throw new Exception("No POST data found.");
            }
        } else {
            // use provided data array
            $this->post_data = $post_data;

            foreach ($this->post_data as $key => $value) {
                $encoded_data .= "&$key=".urlencode($value);
            }
        }

        if ($this->use_curl) $this->curlPost($encoded_data);
        else $this->fsockPost($encoded_data);

        if (strpos($this->response_status, '200') === false) {
            throw new Exception("Invalid response status: ".$this->response_status);
        }

        if (strpos($this->response, "VERIFIED") !== false) {
            return true;
        } elseif (strpos($this->response, "INVALID") !== false) {
            return false;
        } else {
            throw new Exception("Unexpected response from PayPal.");
        }
    }

    /**
* Require Post Method
*
* Throws an exception and sets a HTTP 405 response header if the request
* method was not POST.
*/
    public function requirePostMethod() {
        // require POST requests
        if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
            header('Allow: POST', true, 405);
            throw new Exception("Invalid HTTP request method.");
        }
    }
}
?>

Ответ 3

PayPal отключил SSLv3 в ответ на уязвимость "POODLE". Читайте об этом здесь: Ответ PayPal

Если вы используете ipnlistener.php, заставьте TLS 1.2 в качестве протокола SSL:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); 

(Обновлено: TLS V1.2 требуется на 2017 год)

Примечание. PayPal обновляет протоколы, используемые для защиты всех внешних подключений к их системам. Транспортный уровень безопасности версии 1.2 (TLS 1.2) и протокола передачи гипертекста версии 1.1 (HTTP/1.1) станет обязательным для связи с PayPal в 2018 году. См. Их Дорожная карта безопасности

Ответ 4

SSLv3 больше не доступен для www.paypal.com:

# sslscan www.paypal.com|grep Accepted
Accepted  TLSv1  256 bits  AES256-SHA
Accepted  TLSv1  128 bits  AES128-SHA
Accepted  TLSv1  168 bits  DES-CBC3-SHA
Accepted  TLSv1  128 bits  RC4-SHA
Accepted  TLSv1  128 bits  RC4-MD5

Вы должны изменить CURLOPT_SSLVERSION на TLSv1:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

(Этот "CURL_SSLVERSION_TLSv1" -констант недоступен для старых версий PHP, поэтому другой способ - просто удалить CURLOPT_SSLVERSION.)

Ответ 5

Для меня Ни одна из этих вещей, упомянутых в других ответах, не работала, но я смог выяснить исправление и это по тем же самым строкам, но мне потребовалось некоторое время, чтобы узнать, какой файл, который я использовал sdk, config, так как не было файла прослушивания ipn и что "PPHttpConfig" дал бы мне фатальную ошибку

поэтому я нашел, что это файл-слушатель, который они используют сейчас:

PayPal-PHP-SDK/PayPal/отдых-апи-СДК-PHP/Library/PayPal/ядро ​​/PayPalHttpConfig.php

Я нашел внутри

CURLOPT_SSLVERSION = > 1

Я изменил его на:

CURLOPT_SSLVERSION = > 4

и это исправило это для меня.

Ответ 6

Во-вторых, что. Потерянные часы пытаются понять это. На моем слушателе IPN мне пришлось удалить "force ssl v3". С этого момента мой IPN снова начнет работать.

Просто сделай   curl -v https://paypal.com

Это показывает:   SSL-соединение с использованием TLS_RSA_WITH_AES_256_CBC_SHA

Ответ 7

У меня такая же ошибка при проверке IPN с помощью PayPal. Вот решения проблемы

Я работал с PHP 5.3, а PHP 5.3 больше не поддерживает SSL-версию 3. У меня есть обновление с версией PHP с 5.4 и добавлено ниже строки кода. Это работает для меня.

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_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
#curl_setopt($ch, CURLOPT_SSLVERSION, 4);
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); 
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');

Ответ 8

Используйте этот параметр в своем классе paypal при вызове функции PPHttpPost()

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($ch, CURLOPT_SSLVERSION, 6); //6 is for TLSV1.2