I have an html form which when it gets submitted it calls a JavaScript function which by using Ajax gets information from a PHP file using post and displays it back to the page.
The question is, is it possible to make the PHP file only accessible when using the above method instead of users being able to access it directly if they go through the JS method and find it's location?
Edit: Adding a bit more information to help people out. Ajax is calling an external php file in order to update the contents of the website based on what the php file returns. Since all the Ajax calls are made in the JavaScript someone can easily find out the location and the arguments the function is using and basically call the php file directly, which is what I'm trying to avoid.
Using PHP sessions is a bit hard in this case, since I'm using Ajax I can't destroy the session once the external PHP file is done since if I do the session never renews because I'm using Ajax to update the content of the website without refreshing it.
I agree with limscoder.
Here is how I use tokens on submitting forms.
1) initialize it and save it on server (when the page is loaded on the client side)
$token = $_SESSION['token'] = md5(uniqid(mt_rand(),true));
2) add it to the form
<input type="hidden" name="token" value="<?php echo $token;?>" />
3) when submitted I check the token using
if(isset($_SESSION['token'], $_POST['token']) && $_SESSION['token'] == $_POST['token'])
{
//code goes here
}
It sounds like you're describing a type of cross site request forgery. The normal way of preventing this is by including a server generated token as a form value, and then validating it against a value stored in the user's session when the form is submitted. Check out the link for instructions on how to properly generate and validate the token.
You can test what page called your script by checking the HTTP_REFERER (http://php.net/manual/en/reserved.variables.server.php)
BUT...it can be spoofed, so will only discourage casual attempts at getting to your data
Is the html page secured? If anyone can just access the html page to call your ajax page, why bother to spend time trying to secure it. :)
However if you really need to do so, you might need to convert the html page to a php page so that you can generate a token to be placed in the form. A good token would be the sha of a secret string appended with the year, month, day and hour. When the token is sent back, use the same way to generate a test token and compare the two. This makes the token valid only for 1 hour. Of cause, in the ajax, you might need to test against last hour's token, in case the user got the form at the last minute of the hour and submits after the hour.
Edit---
If your main concern are bots then just use a captcha test.
Related
Guys I have an ISSUE..
I've Created 2 PHP files..
CreateAdmin.php ----------> Has a Form to Fill
Save.php ----------------> Called through jquery Ajax to insert in database.
the codes are working fine. but the problem is i can directly access Save.php file.. when i access each of access an empty row is created in database admin table.
how to prevent it.
actually I've got an idea. when ajax called a session variable should create. the top of the Save.php there should be code if there is not a session variable page should redirect..
is it possible.. if it's okay will it affect the accessing speed.
I would implement some fundamental concepts here. I try to describe them here as simple as possible:
1) In your GET request (calling your CreateAdmin.php) start a session (if not already done) and create a random string that you store to your session:
$_SESSION["token"] = sha256(uniqid(mt_rand(), true));
2) Add the token to your form as a hidden field
<input type="hidden" name="token" value="<?php echo $_SESSION["token"]; ?>">
3) Now do a http POST request with jQuery Ajax call (should not be a GET request). Important include your hidden token from the form. You could also include a special value in your JS that indicate that this is coming form a Ajax call, but this dose not make your Save.php more secure (see below).
4) In you Save.php check first if the call is a POST request, if not do not continue. Than check if the hidden token is included and matching the value in the session (you have to start it), if not do not continue.
if (!isset($_POST['token']) || $_POST['token'] != $_SESSION['token']) die('invalid');
5) If both checks pass you can continue to do your DB stuff but first I would do some additional checks about your data quality that means if the rest of the input is valid e.g.:
Field is not empty if required or the field values has a minimum or maximum length or check if only allow characters included, etc.
6) In all cases I would delete the token from your session.
Generate a new one for the next request if required.
You maybe also want to limit the time how long a token is valid, or check if the user from this session has the right to do this action.
There will be no speed issue with this. There are more things that could be considered but this should be the minimum.
For example you ask that this request should be only possible by Ajax. To be honest I would not take to much effort to check this. You could try to check if the "HTTP_X_REQUESTED_WITH" with "XmlHttpRequest" was included, but this dose not give you much more security. You can simulate a Ajax/POST request very easy in any modern Bowser with the Developer Tools. But with the described method it is not enough just putting the path to your Save.php file in the Browser.
I have set up a rather complicated HTML form that uses the JQuery Validate plugin with several required fields and various rules. Form is working great. It POSTs to a separate PHP processor file that does a number of things such as send a couple of emails and eventually sends the user to Paypal. (It is a club membership application.) It appears that it only took about a week for some type of "bot" to find the processor file and start running it directly over and over. About 500 emails & apps were generated before I caught it and stopped it by renaming the files temporarily. At the time it was happening I wasn't quite sure exactly what was going on, but after evaluating it for most of the day I came to realize that it couldn't be as a result of the main form being executed, but by just running the processor file directly.
So...my question is this: How can I keep this from happening? There must be some type of coding to include that will ensure that the processor can't run unless it is really coming from the real HTML form...or is there a better way? I followed all of the "examples" on the 'Net in regards to forms and POSTing but nowhere did I see anything that relates to this type of problem.
Generally this can be reduced by adding a CSRF token to the form.
Set a random sha/md5 value to your session, and set that value in the form also as a hidden input, upon a legit user sending the form that value will be passed along too, validate and check the passed value with the one in session. if all is good process.
If its a bot, the bot would need to parse the form for the CSRF token first. Or you could step up and make that security key an image and make the user type it (captcha).
How to properly add CSRF token using PHP
Its something you should also add to your login forms ect, else your have bots brute forcing there way in.
Maybe you could add a $_SESSION[] global variable on the form page. Then check it on your processing page and unset it after execution. Sounds like the simplest way to me, but you should hear out what others suggest. You can fin documentation on $_SESSION[] variables here PHP $_SESSION
Add a token to the form when generating the page, and save it into the session.
When you got the post data, check the token with the one in the session.
And you probably want to use CAPTCHA code to protect yourself from the bots.
I have been googling a lot but i am still without an answer so i decided to ask this question here:
Is there a way in PHP how to check that the data i am receiving in some script are from the specific form on the page? I am asking because everyone can see the name of the script i am using for saving the data to my database, so if somebody is able to find out the whole URL, he is also able to send some fake data to the script and i need a condition, that the saving process is triggered only when the data comes from the proper form on my page.
I am using jQuery to call AJAX function, so basically if i click on the button "send", the $.POST() method is triggered to call the script for saving the data.
Thanks,
Tomas
Use tokens to check if request is valid
You could always add some kind of security token when submitting data:
Tokens can be easily extended for many different uses and covers wide area when it comes to checking if some request is valid, for example you could let your non critical forms open for public, ask users to get their secret keys from some page (forcing them to open that page) and then use those keys to identify them when submitting data.
Of course all of this can be completely transparent to user as you could give keys from front page via cookies (or session cookies, it does not matter here, no more or less security as server keys should change after use and invalidate within specified time or when user's identity changes).In this example of use, only user that opened front page can submit data to server.
Another case is when cookies is given away at same page which contains form for submitting data to server. Every user that open page will have their keys to submit data straight away, however if someone tries to make request from outside it will fail.
See OWASP Cross Site Request Forgery
and codinghorror.com Blog CSRF and You
Only with AJAX?
Here is my answer to another question, this answer covers different methods for inserting additional data to ajax request: Liftweb: create a form that can be submitted both traditionally and with AJAX (take a closer look at
$.ajax({
...
data: /* here */
...
Currently I am using tokens this way:
Form used to submit
This hidden input can be added to form, it is not requirement as you can use methods described earlier at another answer.
<input type="hidden" name="formid" value="<?php echo generateFormId(); ?>" />
Function generateFormId()
Simply generate random string and save it to session storage
function generateFormId() {
// Insert some random string: base64_encode is not really needed here
$_SESSION['FORM_ID'] = 'FormID'.base64_encode( uniqid() );
// If you want longer random string mixed with some other method just add them:
//$_SESSION['FORM_ID'] = 'FormID'.base64_encode( crypt(uniqid()).uniqid('',true) );
return $_SESSION['FORM_ID'];
}
Processing submitted form data
if (!isset($_SESSION['FORM_ID']) || $_SESSION['FORM_ID'] != $_POST['formid']) {
// You can use these if you want to redirect user back to form, preserving values:
//$_SESSION['RELOAD_POST'] = $_POST;
//$_SESSION['RELOAD_ID'] = uniqid('re');
echo 'Form expired, cannot submit values.';
//echo 'Go back and try again';
exit(1); // <== Stop processing in case of error.
}
If you need to check which form is submitting data
Then you could just add prefix when generating id's and check for that prefix when processing form data.
This is case when one php script deals with many different forms.
Remember that only ultimate answer to prevent evil users is to pull off all wires from your server...
This is an interesting topic, but you are missing an important point: A spam robot / bad user could also bomb your database by using that specific form page (!).
So, the question is not how to check if the request comes from that page or not, the question is how to check if he's a regular user or a robot/spammer/bot.
Do it with a captcha, like http://www.recaptcha.net
In case i slightly misunderstood the question: If you want to be sure that the request comes from a "real" user you will have to work with a login system / user system and check for users id / password (via db or sessions) every time you want to do a db request.
You can verify that the page is being requested via AJAX with checking against this:
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'
You could also check the HTTP_REFERER.
But it sounds like you're trying to protect a page that processes vulnerable data. This requires more than just the two things above. I'd recommend googling 'CSRF Forgery' to get more information on this.
These are something that you should take a look at.
Capthcas.
Referer check.
Use POST than GET. [Still Curl can automate it.]
From a security standpoint, can someone give me a step-by-step (but very simple) path to securing an ajax call when logged in to PHP?
Example:
on the php page, there is a session id given to the logged in user.
the session id is placed dynamically into the javascript before pushing the page to the client.
the client clicks a "submit" button which sends the data (including the session id) back to the php processing page.
the php processing page confirms the session id, performs the task, and sends back data
I'm stuck on how (and whether) the session data should be secured before sending it through an ajax request. I'm not building a bank here, but i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere (given that sources can be spoofed).
PHP can get the session data without you having to send a session ID via javascript. Just use the $_SESSION variable. If you want to check if a session exists you can just do
if(isset($_SESSION['some_val'))
//do work son.
You'll need to use JavaScript to asynchronously pass user input back to the server, but not to keep track of a session.
Don't send your session data with javascript.
You don't need to (in most cases).
Just post the data with javascript and let PHP retrieve the session data from... the session.
Depends on how you setup your session data.
One simple example would be you have a session called username.
When PHP gets the request from javascript you can do: $_SESSION['username'] to retrieve the sessiondata.
This is a very simple example just to show how it can be done.
As noted above, you don't need to send any session identifiers out with your javascript, to the server an AJAX request is the same as any other request and it will know your session just fine. So basically, just don't worry about it, it's already taken care of.
It's another part of your question that worries me.
i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere
It worries me too; you shouldn't have any "open-ended" PHP pages hanging around at all. Every public .php script should have authentication and authorisation done. The easiest and most maintainable way to achieve this, IMHO, is to have a single controller script (e.g. index.php) that does authentication and authorisation then sends the request to an appropriate controller. Aside from this controller, all other scripts should be outside the document root so that they cannot be called directly.
This means that you only ever have to worry about authentication and authorisation in one place; if you need to change it, it only changes in one place. It means you don't need to worry about accidentally leaving some executable stuff in some library PHP file that's not meant to be called directly. It means you don't need to shag around with mod_rewrite rules trying to protect .php files that shouldn't be in the doc root at all.
I have a PHP script setup using Jquery $.post which would return a response or do an action within the targeted .php file within $.post.
Eg. My page has a form where you type in your Name. Once you hit the submit form button, $.post is called and sends the entered Name field value into "mywebsite.xyz/folder/ajaxscript.php"
If a user was to visit "mywebsite.xyz/folder/ajaxscript.php" directly and somehow POST the data to the script, the script would return a response / do an action, based on the submitted POST data.
The problem is, I don't want others to be able to periodically "call" an action or request a response from my website without using the website directly. Theoretically, right now you could determine what Name values my website allows without even visiting it, or you could call an action without going through the website, by simply visiting "mywebsite.xyz/folder/ajaxscript.php"
So, what measures can I take to prevent this from happening? So far my idea is to ensure that it is a $_POST and not a $_GET - so they cannot manually enter it into the browser, but they could still post data to the script...
Another measure is to apply a session key that expires, and is only valid for X amount of visits until they revisit the website. ~ Or, just have a daily "code" that changes and they'd need to grab this code from the website each day to keep their direct access to the script working (eg. I pass the daily "code" into each post request. I then check that code matches in the ajax php script.)
However, even with these meaures, they will STILL have access to the scripts so long as they know how to POST the data, and also get the new code each day. Also, having a daily code requirement will cause issues when visiting the site at midnight (12:00am) as the code will change and the script will break for someone who is on the website trying to call the script, with the invalid code being passed still.
I have attempted using .htaccess however using:
order allow,deny
deny from all
Prevents legitimate access, and I'd have to add an exception so the website's IP is allowed to access it.. which is a hassle to update I think. Although, if it's the only legitimate solution I guess I'll have to.
If I need to be more clear please let me know.
The problem you describe is similar to Cross-Site Request Forgery (CSRF or XSRF). To protect you against this you could put a cookie into the browser and have the cookie value sent in the post form too (by hidden field or just add it to $.post). On server side check both those fields, if they match the request probably came from your site.
However the problem you describe will be quite hard to protect against. Since you could easily make a script (or use Crul) to forge all kinds of requests and send to your server. I don't know how to "only allow a browser and nothing else".
Use the Session variable as you say plus...
As MyGGAN said use a value set in a cookie (CVAL1) before rendering the submit forms. If this cookie is available (JS Code Check will verify) then submit.
On the server side:
If this cookie value exists and the session variable exist then the HTTP Request came from your website.
Note: If the script (form) is to presented under another domain DO NOT allow the cookie value (CVAL1) to be set.
Do not allow HTTP Requests on the Server Side Scripts if extra Http Headers Are not available (like x-requested-with: jquery). JQuery sends a request with an X-* header to the server.
Read more on Croos-Site Request Forgery as MyGGAN suggests.
I am not really sure REMOTE_ADDR would work. Isnt that supposed to be the end users IP addr?
Firstly, you could make use of
$_SERVER['HTTP_REFERER'], though not always trust-able.
The only bet that a valid post came from your page would be use a captcha.
try to use HTTP_SEC
// SECURITER
if ($_SERVER[HTTP_SEC_FETCH_SITE] != "same-origin")
die();
if ($_SERVER[HTTP_SEC_FETCH_MODE] != "cors")
die();
if ($_SERVER[HTTP_SEC_FETCH_DEST] != "empty")
die();