If someone sees something like
www.whatever.com/purchase.php?price=999
It could be tempting to even an otherwise honest person to change it to
www.whatever.com/purchase.php?price=399
and save themselves $6
Passing the price via the url makes your website highly susceptible to fraud.
That command doesnât even exist in the latest version of PHP and it wouldnât prevent any junk value from being able to be inserted into the database even in old versions of PHP where it did exist.
The best way to prevent injection is to make it completely impossible by using prepare statements. Of course you still need to validate or sanitize ALL inputs to prevent junk insertion.
Thanks for your replies.
Iâd like to determine what the return url (back from Amazon) shows, but it returns so fast I canât tell.
Can you provide a suggestion on how to determine whatâs in that url?
Could you var_dump($_GET) before any other code, then immediately exit?
With regard to the potential for a user changing the parameters by tampering with the URL, this is the reason for the âsignatureâ field. But that script doesnât seem to check it, or (as mentioned earlier) the âresultCodeâ field which may contain âSuccessâ or âFailureâ. The php code just goes ahead and processes the return as if all was fine.
Thereâs some sample code here ( https://github.com/amzn/pay-with-amazon-express-demo/tree/master/php ) in the âSuccess.phpâ that shows how to check the return parameters.
Thanks for your replies.I installed https://github.com/amzn/pay-with-amazon-express-demo/tree/master/php successfully(using Result.php as the return url). Now Iâd like to combine/integrate the code below (which now successfully adds credits to a Usersâ account after purchase) with the git hub code, but I donât know which file from there would be the one to use. Do you know if it would be Result.php or Success.php? Any help will be appreciated. I look forward to your reply. Much thanks again.
<?php
/// - Database Information
$dbhost = 'localhost';
$dbuser = '......';
$dbpass = '......';
$dbname = '......';
$conn = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);
/////////////////////////////////////////////////////////////////////////////////////////
function getUsername($id) {
$sql1 = "SELECT * FROM member_profile WHERE user_id = $id";
$query1 = mysql_query($sql1) or DIE(mysql_error());
$result = mysql_fetch_array($query1);
return $result['user_name'];
}
header('Location: ../index.php');
include_once ('../classes/config.php');
include ('../classes/functions.php');
include_once ('../classes/sessions.php'); //gives us access to the user's cookies for validation
$user = $user_id;
$price = 0;
if (is_numeric($_GET['amount'])) $price = $_GET['amount'];
$username = getUsername($user_id);
$backp = $price;
switch ($price) {
case .10:
$credits = 20;
break;
case .20:
$credits = 40;
break;
case .30:
$credits = 60;
break;
default:
$credits = 0;
}
$sql2 = "INSERT INTO purchases (id, type, user_id, vid_id, date, name, uploader, uploaderID, title, amount, videoid, descr, promo) VALUES ('', 'purchase', '$user', '0', CURDATE(), '$username', 'none', 'none', 'none', '$backp', 'none', 'Purchased via Amazon', 'none')";
$query2 = mysql_query($sql2);
$sql1 = "SELECT * FROM credits WHERE user_id = $user";
$query1 = @mysql_query($sql1);
// =========================================================
// Error reporting for the above query is turned off, so we
// don't know if the credits record was even found.
// The following line fixes that issue by inserting a blank
// record if the row count is zero.
// =========================================================
if (mysql_num_rows($query1) == 0)
{
$sql1_I = "INSERT INTO credits (user_id) VALUES ($user)";
$query1_I = mysql_query($sql1_I) or die(mysql_error());
}
// =========================================================
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// This code may be unneccessary considering an entry is made upon initial user registration.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$old = @mysql_fetch_array($query1);
$balance = $old['total_credits'] + $credits;
$purchases = $old['total_purchases'] + 1;
$sql = "UPDATE credits SET user_id=$user, total_credits=$balance, pending_credits=0, last_purchase=CURDATE(), total_purchases=$purchases WHERE user_id=$user";
$query = mysql_query($sql);
$template = "../themes/$user_theme/templates/main_1.htm";
$inner_template1 = "../themes/$user_theme/templates/inner_amazon_success.htm"; //middle of page
$TBS = new clsTinyButStrong;
$TBS->NoErr = true; // no more error message displayed.
$TBS->LoadTemplate("$template");
$TBS->MergeBlock('mp', $members_full);
$TBS->Render = TBS_OUTPUT;
$TBS->Show();
?>
I think from memory youâd want to integrate your code (though using PDO instead of the old-style mysql calls) into success.php, as you only want to update your database if the purchase has gone through correctly. I canât remember whether the code in result.php passes through the response that you got from Amazon, so that might need changing to ensure the response data is still in place. Also I donât know where your $user_id is coming from, and whether that needs passing through somehow.
Thanks again for your message/help. Much appreciated.
I just got a reply from Amazon that stated âyou should add your credit logic after you have confirmed successful payment. Whether this means adding the code directly to Success.php(code below) or including the AddCredits.php(code above) file is your choiceâ. So, is it possible to add something like
include ('.../AddCredits.php');
to the code below to âadd your credit logic after you have confirmed successful paymentâ, or would it only work if the AddCredits.php code parts - that actually add the credits, be integrated into Success.php?
<html>
<body>
<br />
<p>Your Transaction was successful. Following are the Parameters returned</p>
<br />
</body>
<?php
echo ("<pre>");
print_r($_GET);
echo ("</pre>");
/* begin signature validation */
require_once 'Express.config.php';
$signatureReturned = $_GET['signature'];
$parameters = $_GET;
unset($parameters['signature']);
$parameters['sellerOrderId'] = rawurlencode($parameters['sellerOrderId']);
uksort($parameters, 'strcmp');
$parseUrl = parse_url($returnURL);
$stringToSign = "GET\n" . $parseUrl['host'] . "\n" . $parseUrl['path'] . "\n";
foreach ($parameters as $key => $value) {
$queryParameters[] = $key . '=' . str_replace('%7E', '~', rawurlencode($value));
}
$stringToSign .= implode('&', $queryParameters);
$signatureCalculated = base64_encode(hash_hmac("sha256", $stringToSign, $secretKey, true));
$signatureCalculated = str_replace('%7E', '~', rawurlencode($signatureCalculated));
if ($signatureReturned == $signatureCalculated) {
echo "Signature was successfully validated.";
} else {
echo "Signature does not match.";
}
?>
<html>
You could include the code, or add it directly into the success.php file - thereâs no real difference. By the look of it you need to add your code within the last if () clause where the signature has been found to be correct.
if ($signatureReturned == $signatureCalculated) {
// echo "Signature was successfully validated.";
// Add your processing code here, now you know the signature is correct.
} else {
echo "Signature does not match.";
}
Thanks again for that. Very helpful.
I added the code, and this code appears to work successfully (thanks again).
Can someone please take a peek at it and tell me it is more secure, and if you believe that
the browser bar wonât be able to be edited, as mentioned earlier, to add any additional credits - less suseptible to fraud - and does it help with preventing âjunk insertionâ or âSQL injectionâ?
I look forward to your feedback. Much thanks again.
<html>
<body>
<br />
<p>Your Transaction was successful. Following are the Parameters returned</p>
<br />
</body>
<?php
echo ("<pre>");
//print_r($_GET);
echo ("</pre>");
/* begin signature validation */
require_once 'Express.config.php';
$signatureReturned = $_GET['signature'];
$parameters = $_GET;
unset($parameters['signature']);
if(isset($parameters['sellerOrderId'])) {
$parameters['sellerOrderId'] = rawurlencode($parameters['sellerOrderId']);
}
uksort($parameters, 'strcmp');
$parseUrl = parse_url($returnURL);
$stringToSign = "GET\n" . $parseUrl['host'] . "\n" . $parseUrl['path'] . "\n";
foreach ($parameters as $key => $value) {
$queryParameters[] = $key . '=' . str_replace('%7E', '~', rawurlencode($value));
}
$stringToSign .= implode('&', $queryParameters);
$signatureCalculated = base64_encode(hash_hmac("sha256", $stringToSign, $secretKey, true));
$signatureCalculated = str_replace('%7E', '~', rawurlencode($signatureCalculated));
if ($signatureReturned == $signatureCalculated) {
echo "Signature was successfully validated.";
/// - Database Information
$dbhost = 'localhost';
$dbuser = '.........';
$dbpass = '.........';
$dbname = '.........';
$conn = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);
/////////////////////////////////////////////////////////////////////////////////////////
function getUsername($id) {
$sql1 = "SELECT * FROM member_profile WHERE user_id = $id";
$query1 = mysql_query($sql1) or DIE(mysql_error());
$result = mysql_fetch_array($query1);
return $result['user_name'];
}
//header('Location: ../index.php');
include_once ('../../classes/config.php');
include ('../../classes/functions.php');
include_once ('../../classes/sessions.php'); //gives us access to the user's cookies for validation
$user = $user_id;
$price = 0;
if (is_numeric($_GET['amount'])) $price = $_GET['amount'];
$username = getUsername($user_id);
$backp = $price;
switch ($price) {
case .10:
$credits = 20;
break;
case .20:
$credits = 40;
break;
case .30:
$credits = 60;
break;
default:
$credits = 0;
}
$sql2 = "INSERT INTO purchases (id, type, user_id, vid_id, date, name, uploader, uploaderID, title, amount, videoid, descr, promo) VALUES ('', 'purchase', '$user', '0', CURDATE(), '$username', 'none', 'none', 'none', '$backp', 'none', 'Purchased via Amazon', 'none')";
$query2 = mysql_query($sql2);
$sql1 = "SELECT * FROM credits WHERE user_id = $user";
$query1 = @mysql_query($sql1);
// =========================================================
// Error reporting for the above query is turned off, so we
// don't know if the credits record was even found.
// The following line fixes that issue by inserting a blank
// record if the row count is zero.
// =========================================================
if (mysql_num_rows($query1) == 0)
{
$sql1_I = "INSERT INTO credits (user_id) VALUES ($user)";
$query1_I = mysql_query($sql1_I) or die(mysql_error());
}
// =========================================================
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// That may be unecessary code considering an entry is made upon initial user registration.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$old = @mysql_fetch_array($query1);
$balance = $old['total_credits'] + $credits;
$purchases = $old['total_purchases'] + 1;
$sql = "UPDATE credits SET user_id=$user, total_credits=$balance, pending_credits=0, last_purchase=CURDATE(), total_purchases=$purchases WHERE user_id=$user";
$query = mysql_query($sql);
$template = "../../themes/$user_theme/templates/main_1.htm";
$inner_template1 = "../../themes/$user_theme/templates/inner_amazon_success.htm"; //middle of page
$TBS = new clsTinyButStrong;
$TBS->NoErr = true; // no more error message displayed.
$TBS->LoadTemplate("$template");
$TBS->MergeBlock('mp', $members_full);
$TBS->Render = TBS_OUTPUT;
$TBS->Show();
} else {
echo "Signature does not match.";
}
?>
<html>
I canât comment on the security aspects of the code - by checking the signature based on the Amazon code, that should prevent the chance of someone altering the URL, or calling your return URL with their own parameters, unless they can somehow figure out the signature, but I have no real-world experience on this unfortunately.
The key problem, mentioned above, is that your code uses the old-style mysql functions to access the database. These have been removed from the current version of PHP, so whenever your host upgrades their servers to PHP 7, the code will stop working. Hence, if this is new code, you should take the time to change it to PDO.
This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.