PDA

View Full Version : PHP: Security



Jubba
September 8th, 2003, 12:46 PM
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! (http://reqkills.com/security/test_01.php)) 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 :cowboy:

λ
September 8th, 2003, 01:37 PM
sorry to burst your bubble a little :-\



'HTTP_REFERER'
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.

Jubba
September 8th, 2003, 01:38 PM
yeah I know about that. Like i said, its not an absolute, but on some servers it will provide a bit of a slow down. I'm still working on a more definate method but I am busy with school and such :(

also: the most popular user agents do send the referer information. Mozilla, IE, Netscape.. as far as i know...

ahmed
September 8th, 2003, 01:57 PM
Wow, I never thought of this.. thanks for letting us know, i'll try to think up a method for securing it sorta thing :)

can you just not have the price in the html, but rather have something like itemID=9, and that will look up the items name and the price from a database?

λ
September 8th, 2003, 02:56 PM
Originally posted by Jubba
yeah I know about that. Like i said, its not an absolute, but on some servers it will provide a bit of a slow down. I'm still working on a more definate method but I am busy with school and such :(

also: the most popular user agents do send the referer information. Mozilla, IE, Netscape.. as far as i know...

the point isn't really the fact that they do send it, it's more the fact that it could be tampered with to make it look as if it was running on the server.

I know the problem with school only too well :(

Jubba
September 8th, 2003, 04:06 PM
well true again, but its another varying degree of hacker savvy. Some people don't know it can be tampered with, some don't know how, etc etc... I'm still looking for a more fool-proof method but for now this will slow some people down.

This in itself is not a fail-safe, however this coupled with other checks could help the system to be more secure.. :) Its all part of the discussion and the goal of this thread to help with security :)

Jubba
September 8th, 2003, 04:08 PM
Originally posted by ahmed
can you just not have the price in the html, but rather have something like itemID=9, and that will look up the items name and the price from a database?
Thats what I would have done (and I did do). But some companies don't. If you order something on Amazon.com and view the source in your checkout you can see that the price is included in there with the code, as well as the buyer's identification number and the "receiver's" id number (if they are different).. I could change any of those numbers and potentially cause problems with the amazon page...

Digitalosophy
September 9th, 2003, 06:49 PM
Jubba very useful information. I was thinking what Ahmed advised, that to me would be the best way, why? Becasue I don't know of any other way. Let me ask you this. I know you can pay companies to disable the view source button on the browser, and you could always disable right click as well. I know this is a "patch" and not a solution. But... My question to that is, if I save the web page to my pc, will the html with the prices still be there? Just shooting things off right now.

grandsp5
September 10th, 2003, 03:46 AM
To me, ahmeds solution makes the most sense and is the easiest to pull off. Another thing that might help if you are really concerned is assigning dummy variables. For example, you write the code $price = 10; or whatever and somewhere else you have $item = ID9; where ID9 is your real price. Then they would have to not only find the value of ID9 but if they spent time changing price and finding nothing happens, they might think its protected some other way.

Jubba
September 10th, 2003, 10:48 AM
Dig: Yes if you save the html file to your HD the HTML shows up.

Grand: Yes ahmeds solution is the best way as far as I can tell, but like I said to him earlier, what if you were taking on a job that already had an existing system. The previous coder did not give the database items a unique id number, and there are millions of items. You could overhaul the database, write a script that would insert unique ids for each item, and re-do the coding for each page. Or find a way to make sure that the old way was secure and untamperable...

:) I agree but like I said this is just a discussion of other ideas and possible security issues :)

prstudio
September 10th, 2003, 11:26 AM
jub,
just add the price as a variable on a processing page...

have a form
have it post to a processing page
define money amount on processing page
have processing page route to display

don't include the amount within the form as a hidden field, but instead add it on the back end of things

for example in asp
i would have form

post method yadayada "processing.asp"

processing asp:
dim itemcost
itemcost = "10"


then have an output, as long as the cost is included within the actual code and not the html they won't be able to see it...or make sure to put it in the php tags <? if you are using a GET method.

also with php, do you have server side includes, because a clever trick in asp is to do this


create a page of asp code
save it as pageofcode.inc

then create a second page

default.asp
and have default call the pageofcode.inc

very secure way of hiding junk.

just some thoughts, i didn't go too deep in order to avoid bogging this message down

i never ever put set values into a form

and on the amazon page, those are just report generated, if you did change them and attempt to post them, it would not accept for a variety of reasons, some of which include:

session based logins
cookie based logins
session state changes

randomized ID tags generated on session start

i like doing randomized IDs on my logins, and have them generated client side and server side, then do a check to see if they match, so if a person did edit the information client side, it wouldn't match my database...and it logs all the referrer info so i know who did it ;)

security issues are fun... i really get the most kick out of messing with them
---
oh and if you had an existing database, seems that ive added a column and set it to autonumber and it generated the unique number for me- then you make the the selection look for in the database like SELECT yadda where ID is yadda

hard to say all of this.

Jubba
September 10th, 2003, 12:23 PM
well, yeah. I know all that. I'm not really looking for answers here, just a discussion on other topics. Sessions and cookies and all that are good fixes, but beginners that are looking to do something that involves pricing might not think of that. This thread isn't for me, its a discussion for everyone. Also, includes aren't 100% secure unless they are in a folder that is password protected. I could always find out the name and location of your include file and get to your code that way. :)

prstudio
September 10th, 2003, 12:28 PM
i was just talking about levels, do all the above and you pretty much cover your bases...

i guess i meant it to discuss/help

but whatever, hopefully someone will get something out of it
i would just say if you are a beginner and looking to do this kind of functionality, take a moment out and learn the right way to do it-