Stop Post Data From Different Domain PHP [duplicate]
Asked Answered
W

7

14

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.

Winer answered 1/7, 2009 at 16:38 Comment(4)
I've also tried checking the URL in PHP, but then I found out that was an amateur mistake.Winer
Ok. I've looked over what you guys have given me, and I have thought of a different idea using what you guys gave me...What if I randomized a set of characters => converted to a variable, posted it as the hidden value so it changes every time, and check for that when my script runs?Winer
amateur mistake again.....sorry.Winer
thanks everyone! couldn't have done it without everyone's help!Winer
A
8

$_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.

Allover answered 1/7, 2009 at 16:44 Comment(11)
What if I did randomized the number and posted it as a hidden value, but it changes.Winer
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.Winer
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!Winer
Are you using server side sessions?Allover
No, I am not using server side sessions. And my logic up above didn't didn't work. sorry guys.Winer
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.Winer
figured out how to use the http referer on this page: trap17.com/index.php/…Winer
You can't trust the HTTP_Referrer though, it's easily spoofed.Allover
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?Winer
no kidding, about easily spoofing the http referer - I used the Firefox Add On: addons.mozilla.org/en-US/firefox/addon/953 and quickly spoofed the referer, Thanks for the heads up!Winer
Oh ok, I thought you meant you were only check the Referrer.Allover
E
16

"accepted answer" has security holes. Instead, you should use more secure methods. A simple example:

Step 1: Disable framing of the page (.php), where the form is generated, in the top add:

header('X-Frame-Options: Deny');

Step 2: (important part ! ): In order to avoid XSS and 3rd party exploits, you should create a expirable validation. For example:

  • ASP.NET builtin forms use dynamic input csrf (example value: gtlkjh29f9ewduh024cfvefb )
  • WordPress builtin forms use dynamic input nonce (example value: 340297658942346 )

So, if you are on a custom platform, which doesn't have built-in temporary token validation methods, then implement your approach. A simple concept:

<?php  
$secret_key      = 'fjd3vkuw#KURefg';  //change this
$encrypted_value = Cryptor::encrypt( time(), $_SERVER['REMOTE_ADDR'] . $secret_key);
?>
<form>
...
...
<input value="<?php echo $encrypted_value;?>" name="temp_random" type="hidden"  />
</form>

(Cryptor code is here )

on submission, check:

if(!empty($_POST)){

   // If REFERRER is empty, or it's NOT YOUR HOST, then STOP it
   if( !isset($_SERVER['HTTP_REFERRER']) || parse_url($_SERVER['HTTP_REFERRER'])['host'] != $_SERVER['HTTP_HOST'] ){
       exit("Not allowed - Unknown host request! ");
   }

   // Now, check if valid
   if (   Cryptor::decrypt(  $_POST['temp_random'], $_SERVER['REMOTE_ADDR'] . $secret_key) < time() - 60* 15 ) {
       exit("Not allowed - invalid attempt! ");
   }

   ...........................................
   ... Now, you can execute your code here ...
   ...........................................

}
Egor answered 10/3, 2018 at 12:41 Comment(1)
This allows a 500 Internal Server Error for "Uncaught Exception - Encryption failure" (I determined it to be at line 143 of Cryptor script) when the 'temp_random' string is missing or incomplete (as I tested using Developer Tools.) I resolved this by implementing a "try...catch" statement. I also chose to add a 403 server response for the exit message. Additionally, there is a misspelling of HTTP_REFERERMailman
F
10

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
Foy answered 1/7, 2009 at 16:45 Comment(0)
A
8

$_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.

Allover answered 1/7, 2009 at 16:44 Comment(11)
What if I did randomized the number and posted it as a hidden value, but it changes.Winer
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.Winer
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!Winer
Are you using server side sessions?Allover
No, I am not using server side sessions. And my logic up above didn't didn't work. sorry guys.Winer
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.Winer
figured out how to use the http referer on this page: trap17.com/index.php/…Winer
You can't trust the HTTP_Referrer though, it's easily spoofed.Allover
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?Winer
no kidding, about easily spoofing the http referer - I used the Firefox Add On: addons.mozilla.org/en-US/firefox/addon/953 and quickly spoofed the referer, Thanks for the heads up!Winer
Oh ok, I thought you meant you were only check the Referrer.Allover
D
2

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
}
Daughtry answered 1/7, 2009 at 16:48 Comment(4)
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.Inexact
The "attacker" isn't the client, its another server serving a form page to his clients.Daughtry
Either way it can still happen just as easy.Inexact
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.Foy
B
0

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.

Brittaney answered 1/7, 2009 at 16:45 Comment(1)
Do you even need to check the token in $_POST? Why not just check if the $_SESSION value is still set?Allover
G
0

Every user do signup and then obtain a login id.

Following is algorithm to prevent CSRF: -

1) $login_id = user login id (converted to a numeric id using mysql)
2) $a_secret_key = $_SERVER['UNIQUE_ID'];
3) $remote_addr = $_SERVER['REMOTE_ADDR'];
4) Request Date and Time -> A unique reference key -> $refkey
5) $_SESSION['secretkey'] = $_SERVER['UNIQUE_ID'];

Combine aforesaid 1 to 4 to create a json file, when transferring data to another page.

Then

echo "<input type=\"hidden\" name=\"refkey\" value=\"$refkey\"/>";

At receiver's end:-

Receiver page should check if

1) any json file with $refkey exists at server?

2) If $refkey exists, then check $login_id, $a_secret_key and $remote_addr exists and are correct.
Gambetta answered 9/4, 2018 at 12:37 Comment(0)
E
0

There's a typo in the highest score answer. It should be $_SERVER['HTTP_REFERER'] instead of $_SERVER['HTTP_REFERRER'].

Ephah answered 10/2, 2023 at 19:31 Comment(2)
You should add a comment to the accepted answer with this info instead of creating a new answer.Balkin
@AdrianGhiuta You are correct, however, commenting requires having a minimum of 50 reputation points. Answer and Edit are the only response options available for new members.Mailman

© 2022 - 2024 — McMap. All rights reserved.