验证 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 应该可以工作。
或者,您可以使用gethostbyaddr
或gethostbyname
。
【讨论】:
+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?的主要内容,如果未能解决你的问题,请参考以下文章