动态PayPal按钮生成 - 这不是非常不安全吗?

27

我只是想知道.. 动态创建的PayPal按钮不是非常不安全且容易被"黑客攻击"吗?

例如:

<form name="_xclick" target="paypal" action="https://www.paypal.com" method="post">
<input type="hidden" name="cmd" value="_cart">
<input type="hidden" name="business" value="me@mybusiness.com">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="item_name" value="HTML book">
<input type="hidden" name="amount" value="24.99">
<input type="image" src="http://www.paypal.com/en_US/i/btn/btn_cart_LG.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
<input type="hidden" name="add" value="1">
</form> 

如果你能使用例如FireBug这样的工具修改代码,那么改变产品价格就很简单。

我提问的原因是因为我可能会开始开发一种电子商务系统,该系统可以添加产品,而无需在PayPal中进行操作。


你需要在服务器上验证价格。我不知道你如何使用Paypal完成这个任务。 - SLaks
你能提供一个参考链接,证明你在PayPal开发者网站上看到了那个技术吗? - Kev
使用我下面添加的答案,在更改选项以满足您的需求(例如产品或服务、邮费等)后,它允许您从数据库或任何其他来源提取成本并动态创建按钮。 - lethalMango
@Kev - 当然,给你链接:https://www.paypal.com/cgi-bin/webscr?cmd=p/pdn/article_pdn_storefront-outside - Jeff
@SLaks - 这也是我的想法 - 通过IPN。 - Jeff
显示剩余2条评论
6个回答

48

您应该使用以下 PayPal 按钮 API:

$sendPayData = array(
    "METHOD" => "BMCreateButton",
    "VERSION" => "65.2",
    "USER" => "username",
    "PWD" => "password",
    "SIGNATURE" => "abcdefg",
    "BUTTONCODE" => "ENCRYPTED",
    "BUTTONTYPE" => "BUYNOW",
    "BUTTONSUBTYPE" => "SERVICES",
    "BUTTONCOUNTRY" => "GB",
    "BUTTONIMAGE" => "reg",
    "BUYNOWTEXT" => "BUYNOW",
    "L_BUTTONVAR1" => "item_number=$invoiceNumber",
    "L_BUTTONVAR2" => "item_name=$invoiceType",
    "L_BUTTONVAR3" => "amount=$invoiceTotal",
    "L_BUTTONVAR4" => "currency_code=GBP",
    "L_BUTTONVAR5" => "no_shipping=1",
    "L_BUTTONVAR6" => "no_note=1",
    "L_BUTTONVAR7" => "notify_url=http://www.abc.co.uk/paypal/ipn.php",
    "L_BUTTONVAR8" => "cancel_return=http://www.abc.co.uk/paypal/thanks",
    "L_BUTTONVAR9" => "return=http://www.abc.co.uk/paypal/return.php"
);
您可以使用 cURL 将其发送到他们的 API。
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_URL, 'https://api-3t.paypal.com/nvp?'.http_build_query($sendPayData));
$nvpPayReturn = curl_exec($curl);
curl_close($curl);

然后生成一个加密的HTML按钮,不能被编辑。

<form action="https://www.paypal.com/cgi-bin/webscr" method="post"> 
<input type="hidden" name="cmd" value="_s-xclick"> 
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----
">
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_paynow_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online."> 
<img alt="" border="0" src="https://www.paypal.com/en_GB/i/scr/pixel.gif" width="1" height="1"> 
这些链接应该可以帮助您了解有关按钮选项的信息:

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

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


2
为终端用户简化这个过程是相当容易的。所有选项都是变量,例如 "BUTTONTYPE" => "BUYNOW" 可以是 BUYNOWCARTSUBSCRIBE 等。如果您向用户提供一个表单,并从手册中获取预定义选项,则可以创建一个无需用户编码即可使用的用户友好的PayPal支付系统。否则,安全性将会降低,因此您始终需要设置自己的PayPal账户才能使用所有脚本(据我所知)。在PayPal上轻松点击几下即可获得API密钥,这不应该成为问题。 - lethalMango
@lethalMango 谢谢你的回答。但是假设我需要在Java Web应用程序中执行此操作。因此,我无法通过PHP调用cURL。那么,在这种情况下,我该如何生成动态按钮呢? 如果可以切换到除cURL之外的其他替代方案,那就没问题,请列出任何可行的方案;但是我看到PayPal在其帮助页面中推荐使用cURL来使用buttonManager API。 - nadh
@cURL只是一个HTTP客户端,Java也有一个。 - Jeff
5
比起Paypal文档,这个更加实用。 - Martin
1
@FiddlingAway,仍然安全,可能有API更新,但方法仍然可靠。 - lethalMango
显示剩余13条评论

8
您说得没错 - 如果您以明文形式传递产品价格,动态PayPal按钮很容易被“黑客”攻击。
然而,PayPal支持公钥按钮加密,这样相关细节就不容易被篡改。它的工作方式如下:
- 您使用适当的程序(例如OpenSSL)生成公/私钥对。 - 您登录PayPal帐户并向PayPal提交公钥,然后在Web服务器上安全地存储私钥。您还需要下载PayPal的证书并将其存储在服务器上。还强烈建议告诉PayPal不接受未签名/未加密的交易(有关详细信息,请参见底部链接)。 - 每次您需要生成PayPal按钮时,都要使用PayPal的公钥加密数据并使用私钥进行签名,然后在Web页面上显示结果。当用户单击按钮时,PayPal将解密详细信息并检查它们自生成在您的服务器上以来是否已被篡改。 这样,只要您的私钥没有被泄露,就没有人能够更改交易的细节。
有关更多信息和详细说明,请访问https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_html_encryptedwebpayments#id08A3I0P017Q。(虽然PayPal提供其软件来生成加密按钮,但我认为可以使用适当的函数(例如PHP中的openssl_*())“即时”创建它们;我没有亲自测试过。)
另一种选择是实施即时付款通知(https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro);您可以检查用户执行的交易金额是否等于总订单金额。

我为Jekyll创建了一个插件 - 一种流行的静态网站生成器 - 它使用这种技术(PayPal在其文档中称之为“加密Web支付”)。如果有人感兴趣,插件在这里(是的,我意识到这个问题最初是关于PHP的,只是希望能够帮助那些在静态网站上寻找动态生成和安全的PayPal按钮的人)。 - MoralCode

3

我认为你也可以使用哈希方法,将所有重要的值都哈希处理,这样它们就无法被修改。

目前的方法确实是可破解的,但一旦进入PayPal网站,你仍然可以看到你要支付的金额。用户需要再次确认金额是否正确。


1
您是正确的。 <input type="hidden" name="amount" value="24.99"> 可以很容易地在客户端被篡改。在您提供的示例中,这可能是一个表单,其中客户端实际上应该能够设置金额,例如 PayPal 捐赠按钮。否则,在此表单提交后需要进行服务器端检查,以确保没有任何奇怪的事情发生。

1

-9
我认为我有一个解决这个问题的方法:
首先,从安全页面-公共SSL提交到PayPal。
其次,您可以使用Ajax来防止用户通过“右键单击-查看源代码”或浏览器工具(如Fire-Bug)浏览您的HTML代码。
这是jQuery的一个例子:
我通常使用C#.NET编程,所以这就是我与.ashx通用处理程序进行通信的原因(但它也可以与PHP一起使用)

$(function () {

$.ajax({  
           type: "POST",  
           url: "myPage.ashx",  
           data: {  
               theProductsIdAndAmountsString: yourValue  
           },
           success: function (allHtmlCode) {
               $("body").append(allHtmlCode);
               $("form").submit();
           }
       });
   });

在服务器端,您可以通过从数据库中汇总数据来生成所有HTML表单,然后将其发送回页面。
然后,将其附加到主体并提交表单以进行PayPal支付。

现在,没有人能够使用浏览器工具(如Fire-Bug)更改您的HTML值。


我曾考虑过使用表单提交,但没有使用Ajax,所以+1。我想你不能用FireBug之类的工具编辑Javascript,对吧? :) - Jeff
JavaScript可以通过FireBug进行编辑,但您发送到PayPal的变量将在服务器上生成,无法进行编辑,而且您也无法查看源代码,我已经尝试过了,这是不可能的。<br />但有一些工具可以解码向服务器发送的请求,编辑变量值并使用新值重新请求服务器。这就是为什么您应该使用SSL(https://)来加密向服务器发送的请求并防止这种情况发生的原因。 - Shavit Cohen
6
这种方法没有提供任何安全性。 SSL 没有任何作用,您仍然可以让浏览器向服务器提交任何想要的内容。例如,尝试在浏览器中禁用 JavaScript。然后可以轻松打开 Firebug 并提交表单。这就像把钥匙放在门垫下面一样。 - DaedalusFall
1
另外,您应该查看名为Tamper Data的Firefox扩展程序,每当您向服务器发送请求时,它会停止您的浏览器,让您编辑值,然后继续提交。当然,SSL可以防止APR攻击等,但用户仍然可以完全控制发送的内容。 - Tamás Barta
这不是解决问题的方法。 - user2520969
显示剩余4条评论

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