Фальсификация суммы PayPal
Я никогда раньше не делал интеграцию PayPal, однако я работал с другими шлюзами.
С другими шлюзами есть хеш, который также отправляется в форме сообщения, что не позволяет людям вмешиваться в данные, то есть изменять количество.
Как это вмешательство остановлено с PayPal, похоже, нет никакого хэша.
<form method="post" action="https://www.sandbox.paypal.com/cgi-bin/webscr">
<input type="hidden" value="_xclick" name="cmd">
<input type="hidden" value="online****@theg*****.com" name="business">
<!-- <input type="hidden" name="undefined_quantity" value="1" /> -->
<input type="hidden" value="Order" name="item_name">
<input type="hidden" value="NA" name="item_number">
<input type="hidden" value="22.16" name="amount">
<input type="hidden" value="5.17" name="shipping">
<input type="hidden" value="0" name="discount_amount">
<input type="hidden" value="0" name="no_shipping">
<input type="hidden" value="No comments" name="cn">
<input type="hidden" value="USD" name="currency_code">
<input type="hidden" value="http://XXX/XXX/XXX/paypal/return" name="return">
<input type="hidden" value="2" name="rm">
<input type="hidden" value="11255XXX" name="invoice">
<input type="hidden" value="US" name="lc">
<input type="hidden" value="PP-BuyNowBF" name="bn">
<input type="submit" value="Place Order!" name="finalizeOrder" id="finalizeOrder" class="submitButton">
</form>
Так, как я могу остановить людей, изменяющих сумму перед отправкой в PayPal? Т.е. сумма должна быть 100 но люди меняют ее на 1.
2 ответа
Есть несколько способов предотвратить это. Во-первых, используется уведомление о мгновенных платежах PayPal (IPN). Используя это, вы сравниваете цены, которые PayPal отправляет вам обратно, чтобы подтвердить, что они соответствуют вашим ожиданиям. Если они не совпадают, вы отменяете заказ.
Пример рабочего процесса:
- Пользователь заказывает товар и изменяет цену до $0.01
- Заказ размещен в PayPal, где указана цена 0,01 доллара
- Пользователь принимает цену и платит 0,01 $
- PayPal называет ваш IPN URL и публикует детали транзакции, показывая, что пользователь заплатил 0,01 доллара за вещь
- Ваш IPN проверяет цену, которую PayPal получил (0,01 доллара США), в сравнении с тем, что вы ожидали ( > 0,01 доллара США). Поскольку они не совпадают, вы отменяете заказ
Другой вариант - использовать API кнопок PayPal для создания динамических зашифрованных кнопок. Они встроены в вашу страницу, и пользователь нажимает на нее, чтобы сделать свой заказ. Поскольку он зашифрован, пользователь не может надежно изменить исходный код во время транзакции. Хороший пример этого доступен в этом ответе. Кроме того, вы можете комбинировать это с опцией IPN, перечисленной выше, чтобы служить хорошей проверкой транзакции
Что вам нужно сделать, это внедрить простую систему счетов. В вашей базе данных есть таблица invoices (ID, User_Id, Invoice_Value, Payment_Status)
(пример).
Когда пользователь попадает на страницу оформления заказа, к этому моменту вы должны были вставить запись в таблицу db для этого пользователя на общую сумму, которую он должен заплатить, и начальный статус платежа "Ожидание"). После вставки строки таблицы счетов-фактур получите последний идентификатор вставки и переменную с именем $invoice_id
,
Теперь вы выводите html-форму кнопки оплаты PayPal, и одно из скрытых полей ввода должно выглядеть следующим образом:
<input type="hidden" value="<?php echo $invoice_id; ?>" name="custom">
Теперь, когда PayPal отвечает IPN на ваш обратный URL, ваш обработчик IPN должен вести себя следующим образом:
<?php
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}
// post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen ('ssl://sandbox.www.paypal.com', 443, $errno, $errstr, 30);
if (!$fp) {
// HTTP ERROR
}
else
{
// Make Request To PayPal
fputs ($fp, $header . $req);
while (!feof($fp))
{
// Read Response
$res = fgets ($fp, 1024);
// Check Response
if (strcmp ($res, "VERIFIED") == 0)
{
// PAYMENT VALIDATED & VERIFIED!
// Load the Invoice_Value from invoices table for $_POST['custom']
// and compare it with paypal posted amount held in $_POST['mc_gross']
// if it matches, paypal has authenticated the payment and the value has not been tampered with
// update the invoice table and set the payment status
}
else if (strcmp ($res, "INVALID") == 0)
{
// PAYMENT INVALID & INVESTIGATE MANUALY!
}
}
fclose ($fp);
}
?>