验证 IPN 呼叫来自 PayPal?

Posted

技术标签:

【中文标题】验证 IPN 呼叫来自 PayPal?【英文标题】:Validate that IPN call is from PayPal? 【发布时间】:2011-06-18 09:46:06 【问题描述】:

如何验证对我指定的 notifyURL 的 PayPal IPN POST 请求确实来自 PayPal?

我的意思不是将数据与我之前发送的数据进行比较,而是如何验证此 PayPal 请求来自的服务器/IP 地址确实是有效的?

【问题讨论】:

此处列出的用于验证 IPN 回发来自何处的方法并非万无一失,并且不会真正让您比现在更安全。实施 PayPal 推荐的最佳实践。如果他们不安全,那么 PayPal 就会遇到更大的问题,因为他们的整个品牌都是建立在用户信任之上的。 【参考方案1】:

IPN 协议由三个 步骤:

    PayPal 向您的 IPN 监听器发送一个 通知您该事件的消息 您的听众发送完整的 未更改的消息返回 PayPal;这 消息必须包含相同的字段 以相同的顺序并被编码 与原始消息相同 PayPal 发回一个字,即 如果消息是 VERIFIED 起源于 PayPal 或 INVALID 如果 与之前的内容有任何出入 最初发送

https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro

【讨论】:

谢谢,我知道这一点,我正在这样做……但我怎么能加倍确定它的 PayPal 调用了我的 IPN 侦听器? (您复制粘贴的第 1 步)? 您需要这样做有什么理由吗?毕竟,上面概述的 3 步过程的全部要点是,其他人不可能在呼叫您的 IPN 侦听器的同时仍然得到一个已验证的响应...... 我不是 100% 熟悉中间人类型的攻击,但我认为更谨慎地验证请求来自 PayPal 会更加谨慎......跨度> 或多或少在同一主题上:***.com/questions/2856530/paypal-ipn-security matt74tm:没有什么比“更强大”的了要求。您有两个选项可以指定将其发送到何处:域名或 IP。前者可能(理论上)被接管您的 DNS 服务器的人破坏,尽管这不太可能。后者无法通过 DNS 入侵,但如果 PayPal 更改其 IP,则可能会破坏。【参考方案2】:

这是我发现的最简单的方法,也按照 PayPal 的建议。我使用 http_build_query() 从从 paypal 发送到网站的帖子中构造 url。 Paypal 文档声明您应该将其发回以进行验证,这就是我们对 file_get_contents 所做的。你会注意到我使用 strstr 来检查单词 'VERIFIED' 是否存在,所以我们继续函数,如果没有,我们返回 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;

【讨论】:

实际上,paypal 说你应该把尸体发回给他们:developer.paypal.com/webapps/developer/docs/classic/ipn/… 现在需要 HTTP 标头 User-Agent!【参考方案3】:

现在需要 HTTP 标头 User-Agent!

$vrf = file_get_contents('https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, stream_context_create(array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\nUser-Agent: MyAPP 1.0\r\n",
        'method'  => 'POST',
        'content' => http_build_query($_POST)
    )
)));

if ( $vrf == 'VERIFIED' ) 
    // Check that the payment_status is Completed
    // Check that txn_id has not been previously processed
    // Check that receiver_email is your Primary PayPal email
    // Check that payment_amount/payment_currency are correct
    // process payment

【讨论】:

如果我正在使用沙盒进行测试,URL 是 www.sandbox.paypal.com 还是 www.paypal.com?【参考方案4】:

https://gist.github.com/mrded/a596b0d005e84bc27bad

function paypal_is_transaction_valid($data) 
  $context = stream_context_create(array(
    'http' => array(
      'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
      'method'  => 'POST',
      'content' => http_build_query($data),
    ),
  ));
  $content = file_get_contents('https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate', false, $context);

  return (bool) strstr($content, 'VERIFIED');

【讨论】:

【参考方案5】:

如果我没记错的话,PayPal 使用静态 IP 进行 IPN 调用。

因此,检查正确的 IP 应该可以工作。

或者,您可以使用gethostbyaddrgethostbyname

【讨论】:

+1 提醒我它可能是静态的。我已经好几年没有做任何 IPN 编程了。【参考方案6】:

这是what I use:

if (preg_match('~^(?:.+[.])?paypal[.]com$~', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)

    // came from paypal.com (unless your server got r00ted)

【讨论】:

如果我购买了 blablablarandomstuffpaypal.com 域怎么办?它不匹配这个正则表达式吗? [.] 之前的 paypal 应该可以解决这个问题。 @aularon:因为^,所以不匹配。 很容易被欺骗。见developer.paypal.com/docs/classic/ipn/integration-guide/…

以上是关于验证 IPN 呼叫来自 PayPal?的主要内容,如果未能解决你的问题,请参考以下文章

贝宝 IPN 验证

如何修复 WooCommerce 中的 PayPal IPN 验证错误? [关闭]

PayPal IPN SSL 协议版本

Paypal IPN 已验证,但 Paypal 不断重试

您如何将 Paypal IPN 确认连接到用户?

使用非托管 PayPal 按钮时如何使用 IPN 验证 PayPal 数据