Well, I am working on a small pseudo-e-commerce type test-site and a rather large security flaw came to my attention. This is something that you will see even on larger company sites that sell things over the internet. In HTML there are input tags that allow you to keep information hidden from the browser. That is all fine and good to keep my grandmother from finding out that information but for those of use that are more computer savvy, we know that we can view the source of the document. If you take a look at a lot of these sites you will see that many of them actually have the price of the item(s) as a hidden field!
Now many of these sites probably have strong security features on the backend to make sure that you aren’t tampering with the prices of the items and the other important information. But what about the smaller sites? The ones that you and I create? How do we make sure that no one is tampering with our information? Well there are no real fool-proof ways to stop them. We accept the fact that we are vulnerable and we try our best to make it more difficult for them to hack into our data and have their perverse way with our systems.
Well I intend this thread to be a discussion of various security features for PHP and flaws that people have found, created, or fixed. I will start with this:
–==–==–==–==–==–==–==–==–==–==–==–==–==–==–==–==–
Lets say I have this code:
<?
if($_POST['submit_test']){
$test_bob = $_POST['test_bob'];
$test_price = $_POST['test_price'];
print $test_bob . " costs " . $test_price;
}
?>
<html>
<head>
<title>Security Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<form action="<? echo $PHP_SELF ?>" method="post">
<input type="text" name="test_bob" size="10">
<input type="hidden" name="test_price" value="$10.00">
<input type="submit" name="submit_test" value="test it!">
</form>
</body>
</html>
When you bring up this page (Click here!) the source code looks like this:
<html>
<head>
<title>Security Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<form action="/security/test_01.php" method="post">
<input type="text" name="test_bob" size="10">
<input type="hidden" name="test_price" value="$10.00">
<input type="submit" name="submit_test" value="test it!">
</form>
</body>
</html>
When we run the script with the name “jubba” inputed into the text box our output looks like this:
jubba costs $10.00
You can’t see the PHP code, but you can see the price of the item and the target page that the script runs on, as well as the variable names for the different fields. Using this information we can hack the script and give ourselves a bargain price. Lets say we save the document from our web browser, and dowload it onto our harddrive. We open the page up in dreamweaver and we change a few things around… (changes made are the action atribute in the form tag and the value atribute in the input/hidden tag)
<html>
<head>
<title>Security Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<form action="http://www.reqkills.com/security/test_01.php" method="post">
<input type="text" name="test_bob" size="10">
<input type="hidden" name="test_price" value="$2.00">
<input type="submit" name="submit_test" value="test it!">
</form>
</body>
</html>
Now we upload that script to our own webserver and run the script and our output will look like this:
jubba costs $2.00
We know thats not the right price, but our script doesn’t know that. The script will continue to run. What if the script was supposed to insert those values into a database or charge a credit card account? We would have the wrong values and we would have to spend valuable time fixing the problem.
Now how are we going to fix this problem? Well my solution may not be the simplest, fastest, or even the most secure. I just came up with the fix a day or so ago, and there may be a way around it, there may even be a few things that I am overlooking. However, I am going to show you my solution.
Using PHPs predefined variables we can test the refering webpage against the host domain of the script we are running.
$_SERVER['HTTP_HOST']; // gets the domain of the script
$_SERVER['HTTP_REFERER']; // gets the refering page
Now a function called substr_count(string, substr) will tell us whether the domain name is a substring of the referer script, and if it is, then the script continues processing the informaiton. However, if not then you are given an error message. Here is the code for that:
<?
if($_POST['submit_test']){
if(substr_count($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'])){
$test_bob = $_POST['test_bob'];
$test_price = $_POST['test_price'];
print $test_bob . " costs " . $test_price;
}else{
print "You are accessing this page from an authorized domain.";
}
}
?>
<html>
<head>
<title>Security Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<form action="<? echo $PHP_SELF ?>" method="post">
<input type="text" name="test_bob" size="10">
<input type="hidden" name="test_price" value="$10.00">
<input type="submit" name="submit_test" value="test it!">
</form>
</body>
</html>
Along with the error message I would probably include an IP logger and check that against the number of times that IP or IP group has attempted to access from another domain. If the number is more than 3 or 4 times then it can’t be an accident and I would probably either block their IP from accessing the site all together or severely limit their ability to surf your site…
The page with the fixed script can be found here: http://reqkills.com/security/test_02.php
So, please, test this out so you can see how these things can be exploited. Try it with the first one first, and then try with the second one. Can you get a different price to show? If you can, how did you do it? I am open to any suggestions as this is just something that I came up with quick as another hurdle for someone to cross when attempting to get at my information.
Any questions on this? Any insight that perhaps I missed? Ideas on how to improve this? Any ideas on other security problems with any server-side scripts?
Cheers,
Jubs