Link to home
Start Free TrialLog in
Avatar of trippy1976
trippy1976Flag for United States of America

asked on

Can you determine where a request originates from in PHP script?

I have a script that serves back a graphic.  It includes a database request, but if I can be confident that the request for that graphic originated from my own server, I could skip the DB call and save myself a lot of DB chatter.  Instead, I'd just serve back the graphic.

If I check the referrer and it includes my domain name, is that good?
ASKER CERTIFIED SOLUTION
Avatar of nanharbison
nanharbison
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Dave Baldwin
It's good as long as there is no money involved in doing that.  If there were enough money involved to interest a thief, then you would have to be concerned about the referrer being spoofed.  Otherwise, usually no problem.
Good point Dave!
It takes a lot of effort to fake one of the $_ variables, so you're pretty safe except against some really serious hacking.
You can get a lot of information from the server variables, which you can see here:
http://php.net/manual/en/reserved.variables.php
If you google server variables, you can find tons of tutorials about them, here is one:
http://www.developerfusion.com/article/3703/an-introduction-to-php/5/
This var $_SERVER['HTTP_REFERER']
can be modified chaingin the headers with CURL.

You cann add a bit of security, adding to the request, some encrypted variable joined with a salt.
For example, if the image has a ID, you can define a secret word "secret", and do a md5 as this
$enc = md5("secret".$id);

and validating this string
Avatar of trippy1976

ASKER

I was looking at the $_SERVER['HTTP_REFERER'] thing, but as it mentioned - this seems like it can be fudged pretty easily.  Seems like security by obscurity to me.

Is there anything that is harder to fake, like maybe IP address of the request?  

The script is being called by mod_rewrite, can I do anything at that level?

What I mean is that if you request this from my server:
http://www.mysite.com/images/3000/image.jpg

What will actually happen is you get an image that is served by:

http://www.mysite.com/scripts/getimg.php?id=3000

This is done by mod_rewrite on the server.  But the user doesn't know, they are still using the direct JPG links.

I'm not sure how many thousands of these graphics I serve a day, but I think it's many tens of thousands at the least.  So now with the script in place, it's doing a DB check for every image requested to ensure the user has set that image to publicly accessible.

I'm concerned about the load this is going to place on the database.  So I want to do a (presumably faster) check that determines whether the request is for a graphic embedded in my site or if it's being used at a third party site (which is common for us).

Does $_SERVER['HTTP_REFERER'] seem to work in this use case?
$_SERVER['HTTP_REFERER'] will work, but like anything else, can be faked.

How secure does this need to be?  It takes some knowledge and effort to fake these things, so are these images anything that someone knowledgable enough would be willing to put in the effort to see?
Unless you are charging large amounts of money for each image, I would just 'do it' and not worry about.
The referrer is one good check.  What I might do in addition is put a value into the $_SESSION array and set a corresponding cookie whenever any script in your site is accessed.  You can then test the cookie against the session and have some confidence that they match.  You can reduce the risk of cookie tampering with something like the design shown in this code snippet.  HTH, ~Ray
<?php // RAY_cookie_safety.php
error_reporting(E_ALL);


// DEMONSTRATE HOW TO ENCODE INFORMATION IN A COOKIE
// TO REDUCE THE RISK OF COOKIE TAMPERING


// A DATA DELIMITER
$dlm = '|';

// YOUR OWN SECRET CODE
$secret_code = 'MY SECRET';

// A DATA STRING THAT WE WANT TO STORE (MIGHT BE A DB KEY)
$cookie_value = 'MARY HAD A LITTLE LAMB';

// ENCODE THE DATA STRING TOGETHER WITH OUR SECRET
$cookie_code = md5($cookie_value . $secret_code);

// CONSTRUCT THE COOKIE STRING WITH THE CLEAR TEXT AND THE CODED STRING
$safe_cookie_value = $cookie_value . $dlm . $cookie_code;

// SET THE COOKIE LIKE "MARY HAD A LITTLE LAMB|cf783c37f18d007d23483b11759ec181"
setcookie('safe_cookie', $safe_cookie_value);



// WHEN STORED, THE COOKIE WILL BE URL-ENCODED SO IT WILL LOOK SOMETHING LIKE THIS ON THE BROWSER
// MARY+HAD+A+LITTLE+LAMB%7Ccf783c37f18d007d23483b11759ec181
// IT WILL BE URL-DECODED BEFORE IT IS PRESENTED TO PHP



// HOW TO TEST THE COOKIE
if (isset($_COOKIE["safe_cookie"]))
{
    // BREAK THE COOKIE VALUE APART AT THE DELIMITER
    $array = explode($dlm, $_COOKIE["safe_cookie"]);

    // ENCODE THE DATA STRING TOGETHER WITH OUT SECRET
    $cookie_test = md5($array[0] . $secret_code);

    // IF THE MD5 CODES DO NOT MATCH, THE COOKIE IS NO LONGER INTACT
    if ($cookie_test == $array[1])
    {
        echo "<br/>THE COOKIE {$_COOKIE["safe_cookie"]} IS INTACT";
    }
    else
    {
        echo "<br/>THE COOKIE {$_COOKIE["safe_cookie"]} IS CORRUPT";
    }
}
else
{
    die('COOKIE IS SET - REFRESH THE BROWSER WINDOW NOW');
}




// MUNG THE COOKIE TO DEMONSTRATE WHAT HAPPENS WITH A CORRUPT COOKIE
$_COOKIE["safe_cookie"] = str_replace('MARY', 'FRED', $_COOKIE["safe_cookie"]);

// HOW TO TEST THE COOKIE
if (isset($_COOKIE["safe_cookie"]))
{
    // BREAK THE COOKIE VALUE APART AT THE DELIMITER
    $array = explode($dlm, $_COOKIE["safe_cookie"]);

    // ENCODE THE DATA STRING TOGETHER WITH OUT SECRET
    $cookie_test = md5($array[0] . $secret_code);

    // IF THE MD5 CODES DO NOT MATCH, THE COOKIE IS NO LONGER INTACT
    if ($cookie_test == $array[1])
    {
        echo "<br/>THE COOKIE {$_COOKIE["safe_cookie"]} IS INTACT";
    }
    else
    {
        echo"<br/>THE COOKIE {$_COOKIE["safe_cookie"]} IS CORRUPT";
    }
}

Open in new window

Let me know when you put that script online.  If all you're doing is checking the HTTP_REFERER I would love to come by and see what that graphic looks like.

The point here is that you will only impede or frustrate people who do not know how to use CURL.  The ones who know how to use CURL may be the ones who will steal your graphics.  If you want to post a new question here at EE about how to attack a script that checks HTTP_REFERER I will be glad to show you how ridiculously easy it is to initiate the attack.