Prevent user running own script
Moderator: General Moderators
Prevent user running own script
My site uses HTML buttons (using: form action="process.php" method="POST") to run a PHP code, which queries a database (after validation checks).
My question: recently users have used the HTML source code to view the fields being sent to the PHP script, and then created their own script which runs periodically and submits data automatically. I wish to prevent this. (without captcha)
These users first send their login credentials, and store/use the returned cookie in their script. When the cookie expires they request a new one. The user has all the correct credentials, session IDs, and headers identical to those sent from a browser*. Is there some clever way of distinguishing this script from when a user clicks on the button on my site?
Any ideas / help is appreciated!
*(I did at one point use $_SERVER['HTTP_REFERER'] to check if they were clicking the button on my site, or running the script from their computer. This did work until they modified their script to send all headers identical to a browser's, which they obtained by packet sniffing their own browser when using the site legitimately)
My question: recently users have used the HTML source code to view the fields being sent to the PHP script, and then created their own script which runs periodically and submits data automatically. I wish to prevent this. (without captcha)
These users first send their login credentials, and store/use the returned cookie in their script. When the cookie expires they request a new one. The user has all the correct credentials, session IDs, and headers identical to those sent from a browser*. Is there some clever way of distinguishing this script from when a user clicks on the button on my site?
Any ideas / help is appreciated!
*(I did at one point use $_SERVER['HTTP_REFERER'] to check if they were clicking the button on my site, or running the script from their computer. This did work until they modified their script to send all headers identical to a browser's, which they obtained by packet sniffing their own browser when using the site legitimately)
Re: Prevent user running own script
You need to create a CSRF token and POST that with the form. The server generates a unique token and stores it and populates the HTML form with it.
http://shiflett.org/articles/cross-site ... -forgeries
That's a good article. Defence in depth is important, use HTTP_REFERER, anti-CSRF token, a CAPTCHA, throttle amount of form submitting per second. You won't be able to stop it 100%, but a combination of techniques will really thin down any automated scripts.
hth
http://shiflett.org/articles/cross-site ... -forgeries
That's a good article. Defence in depth is important, use HTTP_REFERER, anti-CSRF token, a CAPTCHA, throttle amount of form submitting per second. You won't be able to stop it 100%, but a combination of techniques will really thin down any automated scripts.
hth
Re: Prevent user running own script
So just to check I understand that correctly:
it says to generate a random variable (which you called a token) when the data is first loaded (via PHP, i.e. invisible to the user), and then check that variable (in the PHP validation, so again invisible to the user) when data is submitted?
What do you mean by "populates the HTML form with it"? Surely you don't want it in the HTML, otherwise the user's script could find it?
And can I just ask a bit about sessions in PHP, as I'm somewhat new to PHP:
1) Is it basically an array that is stored on the server and contains whatever you want it to (and nothing by deafult)?
2) Where is it actually stored?
3) Can it be accessed (legitimately or not) by anything other than my site's own PHP code? Can the user view their own session details?
it says to generate a random variable (which you called a token) when the data is first loaded (via PHP, i.e. invisible to the user), and then check that variable (in the PHP validation, so again invisible to the user) when data is submitted?
What do you mean by "populates the HTML form with it"? Surely you don't want it in the HTML, otherwise the user's script could find it?
And can I just ask a bit about sessions in PHP, as I'm somewhat new to PHP:
1) Is it basically an array that is stored on the server and contains whatever you want it to (and nothing by deafult)?
2) Where is it actually stored?
3) Can it be accessed (legitimately or not) by anything other than my site's own PHP code? Can the user view their own session details?
Re: Prevent user running own script
Session questions:
PHP session data is stored wherever your PHP installation is - I'm not sure of the exact directory. Session data can be only accessed by your site's PHP, however session variables can be intercepted en route if they are not sent over TSL/SSL through packet sniffing. There issues with session hijacking, fixation and spoofing and a malicious user can actually set a session ID to what they want through GET variables.
It is worth reading up on those attacks (Wikipedia is a good place to start). Did you read that article? It provides a good introduction to adding anti-CSRF tokens to your forms.
It works by when the user goes to the form, a token is generated, stored in a session and stored in the form. If the form token doesn't match the session token - they haven't used your websites form and are using a spoof form. This limits them to one attack at a time, through your own form - hardly fruitful!
I hope this helps. I'm sure others have more input.
PHP session data is stored wherever your PHP installation is - I'm not sure of the exact directory. Session data can be only accessed by your site's PHP, however session variables can be intercepted en route if they are not sent over TSL/SSL through packet sniffing. There issues with session hijacking, fixation and spoofing and a malicious user can actually set a session ID to what they want through GET variables.
It is worth reading up on those attacks (Wikipedia is a good place to start). Did you read that article? It provides a good introduction to adding anti-CSRF tokens to your forms.
It works by when the user goes to the form, a token is generated, stored in a session and stored in the form. If the form token doesn't match the session token - they haven't used your websites form and are using a spoof form. This limits them to one attack at a time, through your own form - hardly fruitful!
I hope this helps. I'm sure others have more input.
Re: Prevent user running own script
Yes I did read the link properly, I was just checking that my understanding of it was correct.timWebUK wrote:Did you read that article? It provides a good introduction to adding anti-CSRF tokens to your forms.ArcSaber wrote:So just to check I understand that correctly:
it says to generate a random variable (which you called a token) when the data is first loaded (via PHP, i.e. invisible to the user), and then check that variable (in the PHP validation, so again invisible to the user) when data is submitted?
When you say "token" that is just a normal variable right? You're just using the word token because of how this variable is used, akin to a 'token'?
Why do you say "stored in the form"?
If it is stored in the HTML form (website) displayed to the user (if that's what you mean?) then the user's script can also access it. Can I only store the token in the session, and then say:
$process_token = $_SESSION['token']
somewhere within the process.php code? Thus the token is only ever a server side variable, so the user does not know of its existence. Even if they did know of it, they would not be able to spoof the one-use randomly-generated token (excl. brute force).
However you say a user could use GET variables to access the session and overwrite my token with their own? Can you explain how this would work? If the process can be included as part of a user's script then whilst this method you linked to helps, it is not itself secure.
- flying_circus
- Forum Regular
- Posts: 732
- Joined: Wed Mar 05, 2008 10:23 pm
- Location: Sunriver, OR
Re: Prevent user running own script
1) Yes, pretty much. PHP Sessions, by default, are stored in a serialized array.ArcSaber wrote:And can I just ask a bit about sessions in PHP, as I'm somewhat new to PHP:
1) Is it basically an array that is stored on the server and contains whatever you want it to (and nothing by deafult)?
2) Where is it actually stored?
3) Can it be accessed (legitimately or not) by anything other than my site's own PHP code? Can the user view their own session details?
2) This depends, and you need to know by looking at your specific PHP installation, especially on a shared host. If you are going to use PHP sessions, then you need to change the default save path location. You may get/set the save path by using session_save_path().
3) Refer to number 2. If your sessions are stored in a shared directory, other users who have an account on your web host may be able to manipulate your session data manually. If you've changed the save path to a private directory (which you should!), like a folder in your account's home folder, but outside of the web root, then only your site will be able to manipulate the data. The end user will be able to see the session id, but not the session data. Session id's are transmitted either over get, post, or in a cookie. A cookie is generally the best method.
The concept that Tim is referring to is to use a nonce. This is an access "token" that is a strong random, used to prove the user trying to submit the form data, is the user who accessed the form in the first place. So yes, when the user goes to myform.php, you generate a random string of data and put it into a hidden field inside of the form (the end user can view this). You also store that same token in the user's session (stored on the server side). When the user submits the form, you check that the user is sending you the token that you assigned them:
Code: Select all
if($_POST['nonce'] !== $_SESSION['nonce']) die('Potential Attack'); I believe Tim is trying to confuse you. Session variables are not sent to the end user, they are stored on the server. The only part of the session mechanism that should be sent to the end user is the session id. While a session id can be sent over GET, this presents problems with Dick sharing a URL with Jane that contains Dick's session id in it, hence Jane assumes Dick's session. This is why cookies are the preffered method of transmitting sessions id's.ArcSaber wrote:However you say a user could use GET variables to access the session and overwrite my token with their own? Can you explain how this would work? If the process can be included as part of a user's script then whilst this method you linked to helps, it is not itself secure.
Re: Prevent user running own script
My point was the session_id is transferred over HTTP between client and server, hence why you can obtain it through packet sniffing.
Example of using GET variables:
http://www.example.org/index.php?PHPSES ... dsessionid
Example of using GET variables:
http://www.example.org/index.php?PHPSES ... dsessionid
Re: Prevent user running own script
Unless I am missing something this will not resolve my issue. My problem is not a generic one, but one where the intended user is trying to abuse the system using his specialised automated script. If I implement this method he will simply get his script to scan the HTML form for the hidden token field, and then submit that when his script calls the function.
Maybe I should be more specific with about my site and the issue:
My site is the standard: MySQL database > PHP > HTML, including an HTML button that calls a PHP function (the one the user's script is calling).
The user's script runs by continually requesting the entire web page that would normally be served to a legit user's browser, the script then scans the contents of the page, looks for key numbers, and if they match what he wants then it submits his data, along with the data found in the fields on the page (incl. a token field if I made one), to my PHP function (equivalent of pressing the HTML button). If the scan does not match what he wants, or after it finds what it wants, it simply re-requests the entire web page (after say a 1min delay), thus getting a new token, scans again, etc. etc.
I don't want to count page loads as he'd simply get his script to keep requesting new sessions (something an earlier version of the script did, crashing the website seemingly through too many open sessions). And I can't work by IP as then I would block other legit users from the same IP. If I do anything that is visible to the user (e.g. token, if it must be in the HTML given to the user) then he'll notice and adapt his script. Even one-time usage is one time too many in this case.
My initial fix of scanning for the http referrer was good because it was within the PHP, he never knew it was there. But when his script didn't work he compared what his browser sent to what his script sent, and just copied everything from the browser to his script, including the referrer, although he did not know it was only that which he needed. Now, and because he would modify his script if I changed the fields, I don't see how to distinguish his script from a legit user.
Maybe I should be more specific with about my site and the issue:
My site is the standard: MySQL database > PHP > HTML, including an HTML button that calls a PHP function (the one the user's script is calling).
The user's script runs by continually requesting the entire web page that would normally be served to a legit user's browser, the script then scans the contents of the page, looks for key numbers, and if they match what he wants then it submits his data, along with the data found in the fields on the page (incl. a token field if I made one), to my PHP function (equivalent of pressing the HTML button). If the scan does not match what he wants, or after it finds what it wants, it simply re-requests the entire web page (after say a 1min delay), thus getting a new token, scans again, etc. etc.
I don't want to count page loads as he'd simply get his script to keep requesting new sessions (something an earlier version of the script did, crashing the website seemingly through too many open sessions). And I can't work by IP as then I would block other legit users from the same IP. If I do anything that is visible to the user (e.g. token, if it must be in the HTML given to the user) then he'll notice and adapt his script. Even one-time usage is one time too many in this case.
My initial fix of scanning for the http referrer was good because it was within the PHP, he never knew it was there. But when his script didn't work he compared what his browser sent to what his script sent, and just copied everything from the browser to his script, including the referrer, although he did not know it was only that which he needed. Now, and because he would modify his script if I changed the fields, I don't see how to distinguish his script from a legit user.
Re: Prevent user running own script
Automated scripts? That's pretty generic and happens all of the time.My problem is not a generic one
Let me explain what I use on my forms and I have no issues with automated scripts:
- Anti-CSRF token generated through an AJAX request once the page has loaded
- 5 character alphanumeric captcha
- Check HTTP_REFERER on submittal
- Throttle IP addresses so that too many requests cannot be made
Your issue seems to be an automated script that is just submitting the headers to your actual form over a socket. So they aren't actually using their own form. Meaning your way around this is to set up a captcha (that can expire) so they have to actually manually use your form and to use within a certain time. Also, throttling the IPs would be a big plus, not necessarily banning.
Hope this helps, if not, I must have misunderstood the issue!
Re: Prevent user running own script
I would like to stay away from captcha, as it is in a regularly used form, and would be a large user inconvenience.
I already use HTTP_REFERER, but this is being bypassed in this case.
Problem with IPs is that I have >100 legit users on the same IP (large organisation), so it's not suitable.
Which comes back to the token idea. I'm not too familiar with AJAX, but if it just calls some function (in another PHP file, or whatever) to generate a token, he'd see it in the page source code, so would modify the script to also call that function, thus get its own valid token, and submit it along with the other arguments. Or his script will see (on the fully loaded page a legit browser would see) the already-generated token, and submit that. Either way script still wins?
Or am I missing something?
I already use HTTP_REFERER, but this is being bypassed in this case.
Problem with IPs is that I have >100 legit users on the same IP (large organisation), so it's not suitable.
Which comes back to the token idea. I'm not too familiar with AJAX, but if it just calls some function (in another PHP file, or whatever) to generate a token, he'd see it in the page source code, so would modify the script to also call that function, thus get its own valid token, and submit it along with the other arguments. Or his script will see (on the fully loaded page a legit browser would see) the already-generated token, and submit that. Either way script still wins?
Or am I missing something?
- flying_circus
- Forum Regular
- Posts: 732
- Joined: Wed Mar 05, 2008 10:23 pm
- Location: Sunriver, OR
Re: Prevent user running own script
The token idea is a more reliable solution than the HTTP_REFERER. The referer can be set on the client side, and is trivial to bypass. The token makes it a bit more challenging, but it's not suitable for what you are trying to accomplish.
It's difficult to devise a solution, as your users are supplying legitimate data to your site after being authenticated. If it's a spamming issue, you can throttle the access, or simply tell your user she is in violation of your acceptable usage policy. If you're just trying to differentiate the difference between a human user or a script, some type of turing test is about all you've got. Humans can easily solve phrases like "What is one plus one", but a script will require substantially more time and effort to comprehend and calculate a phrase.
If you need to track a users history, do it based on account, not session.I don't want to count page loads as he'd simply get his script to keep requesting new sessions (something an earlier version of the script did, crashing the website seemingly through too many open sessions).
It's difficult to devise a solution, as your users are supplying legitimate data to your site after being authenticated. If it's a spamming issue, you can throttle the access, or simply tell your user she is in violation of your acceptable usage policy. If you're just trying to differentiate the difference between a human user or a script, some type of turing test is about all you've got. Humans can easily solve phrases like "What is one plus one", but a script will require substantially more time and effort to comprehend and calculate a phrase.
-
cpetercarter
- Forum Contributor
- Posts: 474
- Joined: Sat Jul 25, 2009 2:00 am
Re: Prevent user running own script
You seem to be worried by the fact that a user can "see" the token/nonce in the page source.
The idea is that the token is specific to a particular session. So your hacker can read the token on your web page, but it won't do him any good, unless he also hijacks your session. If he has his own session, he will need a different token.
The system I use (in the PodHawk podcasting software) includes:
- storing session data in the database, rather than in the default php location (which can be insecure);
- a different token for each form, made up from a hash of the page name, a random salt stored in the configuration file, and a random string generated anew for each session;
- sessions data is removed from the database after 20 minutes of inactivity, an action which also terminates the validity of any tokens generated for that session.
This is not foolproof by any means, but it would probably be enough to stop the mischief which you are suffering.
The idea is that the token is specific to a particular session. So your hacker can read the token on your web page, but it won't do him any good, unless he also hijacks your session. If he has his own session, he will need a different token.
The system I use (in the PodHawk podcasting software) includes:
- storing session data in the database, rather than in the default php location (which can be insecure);
- a different token for each form, made up from a hash of the page name, a random salt stored in the configuration file, and a random string generated anew for each session;
- sessions data is removed from the database after 20 minutes of inactivity, an action which also terminates the validity of any tokens generated for that session.
This is not foolproof by any means, but it would probably be enough to stop the mischief which you are suffering.
- kaisellgren
- DevNet Resident
- Posts: 1675
- Joined: Sat Jan 07, 2006 5:52 am
- Location: Lahti, Finland.
Re: Prevent user running own script
Wow, they certainly took the hardest path...ArcSaber wrote:they modified their script to send all headers identical to a browser's, which they obtained by packet sniffing their own browser when using the site legitimately
Nonces in the form are not the answer here. Automated bots will gather them and send them just like your users' browsers.
What is the reason you do not want to use a CAPTCHA? It would probably be the most reliable friend. Another choices include CSS and JavaScript client-side tricks, but they can be beaten.