views:

101

answers:

3

Hi All,

I am developing one web application ( using php), I want to provide more security to application so that no one can easily break the functionality.

Brief explanation about my problem : In one module there is one stage where I am checking the source of the request ( from where this request is coming from )

Currently, I am using HTTP_REFERRER variable ( available in php ). I am checking this variable value with one specific URL (e.g. http://www.abc.com/test.php ). If exact match exist then only I am calling further actions.

I am bit confused with above approach, whether should i use HTTP_REFERRER or check with IP address( valid request if it is coming from any specific IP address )? I also want to know better approaches for providing security.

Is anyone has idea then please share... ?

Thanks in advance - Pravin

+4  A: 

Lesson #1 in web security: NEVER trust user input. And when I say never, I mean never. ;) Including the HTTP_REFER var in PHP which is easily compromised with an http header (source: http://www.mustap.com/phpzone_post_62_how-to-bypass-the-referer-se)

A possible solution in checking the source is the using a form token (csrf protection): http://www.thespanner.co.uk/2007/04/12/one-time-form-tokens/ but isn't that safe either and is only possible with your own source.

What is the exact use case, because there are several methods to secure your website.

Update:

A simple CSRF (cross-site request forgery) protection example: (Hence the simple. For a more safe/robust solution, refer to the answer of The Rook)

1) In your form page, create some kind of token and put in your session and in a hidden form field:

<?php
    session_start()
    $csrfToken = md5(uniqid(mt_rand(),true)); // Token generation updated, as suggested by The Rook. Thanks!

    $_SESSION['csrfToken'] = $token;
?>
<form action="formHandler.php">
   <input type="hidden" name="csrfKey" value="<?php echo $csrfToken ?>" />
</form>

2) In your form handler check if the token is valid.

<?php
   session_start();
   if($_POST['csrfKey'] != $_SESSION['csrfKey']) {
      die("Unauthorized source!");
   }
Treur
Thanks folks for quick response, @Treur : My valid test case is :I am posting some values like 'age' , 'id' , 'description', 'remarks'using simple form method i.e. post.I am posting this to one specific URL which is actually proceeds on these values which should be secured.So here I want to check where the source of the request is valid or not. ?
pravin
In that case you want to use some kind of csrf protection. I've updated my answer with a simple example
Treur
-1 the refer is safe for csrf protection, and your csrf token generation is very insecure, this is better: `uniqid(mt_rand(),true);` The attacker is going to know the time, after all he can control when the request is sent.
Rook
It doesn't matter if he knows the time, because it is combined with a 'secret' salt. I did called it a simple example on purpose ;)
Treur
@Treur yeah your right its not trivial to bypass, but you should still have more entropy, even calling mt_rand() would be better. Using a known value such as the time or url bothers me. I added some whitespace to your post just to take away the -1.
Rook
@Treur I thought of another attack against your `csrfkey`. If the attacker creates and account and logs in then he will know the exact `microtime()`, using this known value he can then use John The Ripper to brute force the `md5()` hash to obtain the salt value. In short, this csrf token generation is not good and you should change this post.
Rook
@The Rook. True. However. I wonder. I'm not really into the inner workings of pseudo random number generators. (mt_rand) Aren't they based on the microtime as well an therefore in theory traceable as well? (But perhaps I should ask that in a separate question)
Treur
+1  A: 

Checking the HTTP_REFERRER for CSRF is a valid form of protection. Although it is trivial to spoof this HTTP header on your OWN BROWSER it is impossilbe to spoof it on another persons browser using CSRF because it breaks the rules.

According to the Department of Homeland Security I have found the most dangerous CSRF vulnerability ever found and is in the top 1,000 most dangerous vulnerabilities of all time. Motorola patched this flaw using a referer check, and its common to see this protection method on embedded network hardware because memory is scarce.

A more common and more secure method is to store a Cryptographic nonce inside a $_SESSION variable and check this for each sensitive request. An easy approach is to use POST for all sensitive requests (like changing your password) and make sure this Cryptographic nonce is valid for all posts in a php header file, if it isn't valid then unset($_POST);. This method works because although an attacker can force your browser into SENDING GET/POST requests he cannot view the RESPONSE, and there for cannot read this token needed to forge the request. This token can be obtained with XSS, so make sure you test your site for xss.

A good method for generating a csrf token is md5(uniqid(mt_rand(),true)); This should be enough entropy to stop CSRF. md5() is used to obscure how the salt is generated. Keep in mind that the current time is not a secret, the attacker knows exactly what time the CSRF request is produced and can narrow down when the session was created. You must assume that the attacker can make many guesses, and in practice this is simple to accomplish by writing a bunch of iframes to the page.

Rook
He is right you know ;)
Treur
Sorry, but using the referrer header is NOT a valid CSRF protection. The referrer header is optional and it may be omitted by the browser at any time (rfc2616, HTTP 1.1) and it is possible to spoof it.
Kim L
Oh, and using a session variable is not safe either. Consider the following case: When the user enters the page with the form, you create your secret token and set it as a session variable, when the user submits the form, the script checks for the token, if it's valid, the action is executed. This can be attacked simply by using an iframe and some javascript. The attacker can trick the user into visintg a malicious site. The malicious site contains an iframe which loads the target site's form (token is now set). The attacker uses a javascript timer to change the the iframe's source (continues)
Kim L
(continuation to previous comment) to the target CSRF url. The URL is requested and the session variable is set, thus the action is processed.
Kim L
@Kim L So how many CSRF exploits have you written? I've written a lot of them, and thats why I know what you are describing is a clear violation of the same origin policy. You need to read the Google browser sec handbook and then try this attack. (It will never work :)
Rook
@Kim L Another thing, Motorola surfboard cable modems are very popular, chances are you have on in your house. Go to `192.168.100.1` and try and write a CSRF exploit to restart the modem.
Rook
@The Rook, sorry, re-read your post and what you described will work as it is basically the same I described in my reply, just another strategy for creating the secret token. I first read that your post was about a multi-paged form, which I described an attack for (it will work if the pages are predictable and thus there is no need to read the HTTP response). My attack is valid and doesn't conflict with the same origin policy, as it never requires to read the response. In other words, my bad. If you still think my attack is not valid, I can provide you with a proof-of-concept :)
Kim L
@Kim L the referer cannot be modified by the attacker using CSRF and I'm not sure how an iframe helps in this attack.
Rook
@The Rook, like I said, I misread your response and my comment was about multi-paged forms. The iframe only helps when attacking multi-paged forms, it had nothing to do with the referer header. Here's an example of how an application can be tricked into thinking the referrer is something else than what it actually is. This attack doesn't actually spoof the referer header, but rather demonstrates that everything isn't exactly what you think it is. Make sure you read other blog posted linked to in the beginning. http://blog.quaji.com/2009/08/facebook-csrf-attack-full-disclosure.html
Kim L
@Kim L nice blog post.
Rook
A: 

Treur got it right, but I still want to clarify a few things and provide you with some sources for reference material. As Treur said, NEVER ever trust user input data, that includes all headers sent by the browser.

What you are describing, is a typical Cross-Site Request Forgery attack. Checking the referrer header is not a valid protection against CSRF attacks, since according to the RFC2616 (Hyper Text Transfer Protocol 1.1), the referer header is optional and thus may be omitted by the browser at any time. If you are using SSL, then the referer header is always omitted by browsers. Secondly, it is a user defined value, and thus should not be trusted.

The recommended protection against CSRF attacks is to use the synchronized token pattern. This means that you should create a secret token which is embedded as a hidden field in your form. When the form is posted, you verify that the secret token is present and that it is valid. There are multiple strategies for creating security tokens. I'll describe one way for creating the tokens:

For each action in your application, create a unique action name for them. For example, "delete_user", "add_user" or "save_user_profile". Let's say that the form you described has the action name "foobar". Concatenate the action name with the user's session id and a secret value.

$stringValue = "foobar" . "secret value" . session_id();

To create the security token, create a hash of the concatenated string, you can use sha1 to create the hash. To decrease the risk of brute force attacks, use a larger key in the hash, for example, sha 512.

$secretToken = hash("sha5125", $stringValue);

Set this token in your form's hidden field. When the form is submitted, recreate the token and verify that it matches the one submitted in the form. This token is valid for one user session. One may argue, that there is a window of opportunity where an attacker can reuse the token as it is not regenerated at every request. However, with proper session management strategies, this shouldn't really be a concern.

Like I said, proper session management is necessary. This means that you shouldn't keep the sessions alive to long. Especially session fixation vulnerabilities will undo any CSRF protection measures, as the attacker is then in control of the user session and hence can "predict" the secret tokens.

Here are a couple of links that I recommend you read through:

Kim L