PayPal IPN 安全性

7

PayPal IPN会向通知URL发送一个具有变量数量字段的POST请求,为了确认该POST请求的合法性,我们需要重新提交相同的请求,并附加一个额外的cmd=_notify-validate字段到PayPal,然后PayPal会回复VERIFIEDINVALID

我的问题是,为什么我们需要重新向PayPal发送请求呢?难道像这样不就足够了吗?

if (preg_match('~^(?:.+[.])?paypal[.]com$~i', gethostbyaddr($_SERVER['REMOTE_ADDR'])) > 0)
{
    // request came from PayPal, it's legit.
}

如果我们可以相信服务器正确解析IP地址,那么我认为我们可以相信PayPal的所有请求,不是吗?
6个回答

7

这是我发现的最简单的方法,也是PayPal建议的。我使用http_build_query()从PayPal发送到网站的post构造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;

当然可以,但我认为你没有完全理解我的问题。 - Alix Axel
这是你第二次发布相同的答案(第一次在此处:https://dev59.com/z1PTa4cB1Zd3GeqPnN-K#6710154)。重复使用相同的示例是可以的,但请考虑更具体地针对每个问题调整你的答案。 - Tim Post
3
如果有人成功地欺骗了 IP 地址,那么你就惨了。我在这里提供同样的答案是因为人们在搜索如何验证 PayPal IPN 时找到了这篇文章,而原始帖子绝对不是正确的方法。请注意,本句中的“up shit creek”为俚语,意思是“陷入困境”。 - Lobos

6

为了使你的网站/应用程序受益,PayPal只是执行更高标准的安全性。

IP欺骗可以轻松欺骗你的示例函数,因为仅依靠REMOTE_ADDRESS很容易遭受攻击。

在进行金融交易时,安全性至关重要。如果我可以伪造一个IPN请求,我就可以欺骗你的网站/应用程序执行虚假交易。通过发送额外的请求到已知和可信的位置,我们获得了更高标准的凭据,以便采取行动。整个原始IPN请求都会在此确认中发送,以便PayPal可以验证所有交易详细信息确实有效,从而防止中间人攻击,即攻击者修改PayPal向您的服务器发送的有效请求的详细信息(例如更改价格或数量)。


我理解PayPal的立场,并且我完全同意MITM漏洞(尽管我有这样的印象,这种攻击在现实中比理论上难得多)。我不明白的是如何欺骗REMOTE_ADDR - 能否给出一个(实际的)例子? - Alix Axel
1
编辑时将“also”更正为“as”,我是指IP欺骗是一种更改REMOTE_ADDRESS的方法。对于大多数设置/目标来说,欺骗可能是不可能的(但在WiFi热点、学生宿舍和其他共享上行链路的广泛开放子网中不是)。一旦您将自己定位为邻居,更改数据包就相当容易了。 - defines

5
我知道这个问题很老,但是:
攻击者甚至不需要欺骗他的IP地址或执行任何类型的MITM来通过您的验证:
1. 攻击者使用IP地址x.y.z.t从他自己的机器连接。
2. 您的服务器调用gethostbyaddr(“x.y.z.t”),该函数向名称t.z.y.x.in-addr.arpa发送dns查询。
3. 如果x.y.z.t属于攻击者,那么他控制(至少)dns域z.y.x.in-addr.arpa(因为它包含他自己的ip)的机会很大。 因此,他可以在响应该查询时返回“paypal.com”。
4. 您的服务器从攻击者的dns服务器接收到“paypal.com”,并且您的验证检查成功。
可以通过像Lobos建议的那样向PayPal发送请求来击败此攻击。

2
整个系统如果有人成功修改运行您的IPN监听程序的机器上的hosts文件,则会崩溃;
坏人发送虚假付款通知;
您的受损服务器向“paypal.com”发送重复信息,实际上指向了坏人的计算机;
坏人回复“已验证”,像已经支付一样收到货物。
这不是一个大问题,因为如果一个人有读写访问您的hosts文件,他们可能只需手动将付款记录放入您的数据库中,或者造成其他很多破坏。
这只是一个想法。

1

这里有一个回复POST请求的原因,来自于IPN指南

您的监听器必须对每个消息进行响应,无论您是否打算对其进行任何操作。如果您不做出响应,PayPal会认为该消息未被接收并重新发送该消息。PayPal会定期重新发送该消息,直到您的监听器发送正确的消息为止,尽管每次重发消息之间的时间间隔都会增加。

重要提示:PayPal希望在30秒内收到IPN消息的响应。


这实际上是Paypal提供的非常误导性的信息。所需要的是您用HTTP 200回应他们的POST请求并且没有数据。您不需要按照人们以上所描述的方式验证Paypal的数据。下面是非常重要的步骤:1)Paypal向您的服务器发送POST请求,2)在单独的连接上,您将数据再次发送回Paypal,3)Paypal会响应已验证(或未验证),4)您使用空200回复Paypal的原始POST请求。 - Dom

0

1
你知道我是这个问题的提问者,而你却在链接到我的另一个答案吗?:-P - Alix Axel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接