tags:

views:

578

answers:

5

I'm a beginner in PHP.

What I'm trying to do is stop Post Data coming from another webpage.

The problem I am having is let's say someone copies my form and pastes it in their website. I want to be able to stop that Post Data from running the script on my email form.

How can I do this? Let me know if I'm not being clear enough.

My PHP Contact form runs on one page with conditional statements. i.e. if data checks out, submit.

+4  A: 

$_SERVER['HTTP_Referrer'] would be nice but it isn't reliable. You could use a hidden form field that MD5's something and then you check it on the other side.

AndyMcKenna
What if I did randomized the number and posted it as a hidden value, but it changes.
Juan
oh wait, they can just remove that hidden value and make it work....lol. dangit,just when I think i'm getting the grips of PHP.
Juan
I think I finally figured it out, I used session_start, made a sessions variable when the form was shown, and then checked to see if the variable was set to submit!
Juan
Are you using server side sessions?
AndyMcKenna
No, I am not using server side sessions. And my logic up above didn't didn't work. sorry guys.
Juan
the only problem when I MD5 my string is that, the person can grab that hidden value and place it on their site. This will only work temporarily until a new string is generated in the hidden value. in other words until someone refreshes the page.
Juan
figured out how to use the http referer on this page: http://www.trap17.com/index.php/Check-Referrer-Prevent-Linking-Sites_t40295.html
Juan
You can't trust the HTTP_Referrer though, it's easily spoofed.
AndyMcKenna
yeah, i'm also using the randomized hidden field and checking it before submit using sessions. any other ideas that are useful for checking unique user identity and preventing CSRF?
Juan
no kidding, about easily spoofing the http referer - I used the Firefox Add On: https://addons.mozilla.org/en-US/firefox/addon/953 and quickly spoofed the referer, Thanks for the heads up!
Juan
Oh ok, I thought you meant you were only check the Referrer.
AndyMcKenna
A: 

If you're looking for a quick-and-dirty approach, you can check the REFERER header.

If you really want to make sure that the form was fetched from your site though, you should generate a token each time the form is loaded and attach it to a session. A simple way to do this would be something like:

$_SESSION['formToken'] = sha1(microtime());

Then your form can have a hidden input:

<input type="hidden" name="token" value='<?=$_SESSION['formToken'];?>' />

and you can check that when deciding whether to process your form data.

Peter Stone
Do you even need to check the token in $_POST? Why not just check if the $_SESSION value is still set?
AndyMcKenna
+2  A: 

You're trying to prevent CSRF - Cross-Site Request Forgery. Jeff himself has a blog article about this.

True XSRF Prevention requires three parts:

  • Hidden Input Fields, to prevent someone from just snatching the form and embedding it
  • Timechecking within an epsilon of the form being generated, otherwise someone can generate a valid form once and use the token (depending on impementation/how it's stored)
  • Cookies: this is to prevent a malicious server from pretending it's a client, and performing a man-in-the-middle attack
Tom Ritter
A: 

Add two hidden fields like this:

<?php
$time = time();
$_SESSION['time'] = $time;
/*
 *This is a Perfect Password from Steve Gibbson's site https://www.grc.com/passwords.htm
 *It should make for a great Salt.
 */
$salt = 'b79jsMaEzXMvCO2iWtzU2gT7rBoRmQzlvj5yNVgP4aGOrZ524pT5KoTDJ7vNiIN';
$token = sha1($salt . $time);
?>
<input type="hidden" name="token" value="<?php echo $token; ?>" />

Then when you do the authentication you'll use code like this:

<?php
$salt = 'b79jsMaEzXMvCO2iWtzU2gT7rBoRmQzlvj5yNVgP4aGOrZ524pT5KoTDJ7vNiIN';
$token = sha1($salt . $_SESSION['time']);
if($token != $_POST['token'])
{
die('you stupid scum sucking bandwidth hog!');
}
//Rest of form validation
?>

This is not a perfect system and it could be cracked, however one of 2 things would be needed to crack it:

  1. Your salt (be sure you keep it secure)
  2. ALOT of time, this could take several thousands of years to brute force so don't worry about this.

EDIT: I updated my answer to account for the obvious mistake I made, pass at least the time variable in the session if not both, the time and the hash. Assuming that your using server-side sessions and not cookie sessions then they cannot be tampered with unless someone has access to the server, in which case your already screwed.

Unkwntech
The attacker could easily embed a valid `time` and `token` field in their form. They don't have to know the salt to copy the values out of your form.
Matt Bridges
@Matt, how about that I was just saying more or less the same thing about your answer.
Unkwntech
You'd DEFINETLY need to validate that the time was within a certain epsilon.
Tom Ritter
The value that you are hashing cannot be in the form itself or else the attacker can just permanently use that value.
Matt Bridges
Malicious Website: MW. Malicious Server: MS. Legit Server with this protection: S. User visits MW. MW makes an AJAX call to MS, MS remote-loads the website from S, returns the time and token to MW. MW fills in the values and submits the form. Token and Time are legit, and within an epsilon. You also have to add in cookie authentication to completely prevent this.
Tom Ritter
cookie auth is editable by the user, hence what I said about using a server-side session var.
Unkwntech
After the Edit: Does PHP invalidate a session if it's accessed from two different IP addresses? If not, depending on how sessions are configured, I can refuse cookiees on the MS when I set up the remote-load, and generate a ?PHPSID which I would include as the client submits the form.
Tom Ritter
I'm not sure, I've never tried, but that seems as if it could, one might store a cookie on the user with the HASH of the IP + salt then verified on reload but still you have the problem that the REMOTE_ADDR can be spoofed and cookies can be modified or rejected entirly.
Unkwntech
Seems I need to sleep, because after pulling an all nigher (up >18 hours now) I seem to be making rookie mistakes.
Unkwntech
A: 

In the form:

<?
$password = "mypass"; //change to something only you know
$hash = md5($password . $_SERVER['REMOTE_ADDR']);
echo "<input type=\"hidden\" name=\"iphash\" value=\"$hash\"/>";
?>

When you are checking:

$password = "mypass"; //same as above
if ($_POST['iphash'] == md5($password . $_SERVER['REMOTE_ADDR'])) {
    //fine
}
else {
    //error
}
Matt Bridges
REMOTE_ADDR could be spoofed, so if there were a MITM attack this would prove worthless. Also after I've made a single request I could easily make more by simply duplicating the hash, which would render this worthless, the 'unique' part of the hash needs to be more 'unique', which is why I chose to use time() witch provides the current epoch time.
Unkwntech
The "attacker" isn't the client, its another server serving a form page to *his* clients.
Matt Bridges
Either way it can still happen just as easy.
Unkwntech
I believe the same AJAX-Remote-Loading comment on Unkwntech's answer applies to this as well. True XSRF protection requires cookies, hidden form input, and time-within-epsilon considerations.
Tom Ritter