I have a website where, when visitors land on any of a several landing pages (different languages), they are given an opportunity to enter any of a number of promotion codes into a form. If they enter one of the correct codes (stored on a SQL table), they go to another page with a form where they can give their mailing info to receive a free product. If the code they entered isn't on the table, they get a message the code they entered is invalid and are blocked.
This works through php. When the landing page form is entered and submitted, a URL something like this: website.com/formentry.php?promo=code is generated where 'code' matches whatever the user entered into the form. If “code" matches a string in the code column in the database table, they get sent to the entry form. If it doesn’t, they get blocked. To this point, everything works great and has been running smoothly for months.
However a problem has been identified recently: The landing pages can be circumvented by entering website.com/formentry.php?code=code directly into a browser’s URL field. This is a problem for several reasons and I need to prevent it from being possible.
Does anyone have any ideas for a solution; perhaps using the .htaccess file to send those URL requests back to the landing page?
Using sessions, you can set the user's session when they enter the correct code on the landing page:
session_start();
$_SESSION[valid_user] = true;
Then, on every other page (non-landing-page), you put a validator like:
if (!$_SESSION[valid_user])
{
echo "You do not have permission to view this page";
}
Or, instead of showing an error message, you can redirect the user to another page:
if (!$_SESSION[valid_user])
{
$url = "http://example.com";
header("Location: $url");
exit();
}
If you want to take this one step further, let's say the auth. code is 420. You can set the landing page to take the submitted code and set
$_SESSION[420] = true;
and on the page for product #420, or whatever, validate, as above, that the user's session contains 420 == true
. That way, if they use coupon code 420, they're only authorized to see product #420's page, not all product pages.
Pass the promo codes not via URL, but through sessions.
You could solve it and at the same time protect your self from Cross-Site Request Forgery (CSRF).
Here is how:
In many ways this give your a better protection.
Some sample code you could use.
<?php
// In the page you have the form:
// Generate the string
$csrf_value = str_replace(['/', '+', '='], '', base64_encode(random_bytes(20)));
// Save it in the session
$_SESSION['csrf'] = $csrf_value;
?>
<form action"a_page.php" method="POST">
<input type="hidden" name="csrf" value="<?php echo $csrf_value ?>" />
<input type="textfield" name="code" />
</form>
In the page that receives the request:
<?php
if (isset($_POST['csrf'])
&& strlen($_POST['csrf']) > 0
&& strcmp($_SESSION['csrf'], $_POST['csrf']) === 0) {
// All good, do your thing
} else {
// Show error, this guy is trying to trick you
}