tags:

views:

346

answers:

3

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.

+2  A: 

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".

MyGGaN
Tim here:Well, so far I am also modifying the path to the ajax script so that it is loaded through another php script, thus allowing me to NOT show the actual path to the script within the html of the page. If they somehow find out the script path, I still have an issue though.
Joe
*see my updated response above everyone
Joe
*... not directly above, but under the Question area :P haha
Joe
Could you describe how you obfuscate the path to the script? The form ($.post) needs to know where to send the data. So I can just look at your source code and see where the request is supposed to be sent and send my forged data there. Please explain how you could avoid this.
MyGGaN
Tim here:To obfuscate the path you simply do it like this:ajax_file = "<?php echo encyryptstring("AjaxScriptFile.php");?>";$.post("poster.php", {ajax_file: ajax_file})Then, inside "AjaxScriptFile.php" you:include("somefolder/".decryptstring($_POST['ajax_file']));// You could also try omitting the .php and adding that inside too. Use whatever encrypt/decrypt string you like. You would need to have all your ajax files in the same folder though, otherwise you'll need seperate loader.php files for each folder you're using to keep those folder names hidden from the user.
Joe
Btw I'll be using my first name instead of my other name from now on :) good site this helpful ppl here
Joe
Sorry I meant inside "poster.php" not inside "AjaxScriptFile.php"
Joe
This doesn't help you, since you'll have to tell my browser how to decrypt the path I could just figure it out the same way as my browser will. This seems like unnecessary work for nothing. And if you still proceed with this attempt you better check that $_POST['ajax_file'] good before including it in your php script!!! Else you might find someone posting with eg. '../config.php' and you'll not know what can happen.
MyGGaN
The '../config.php' would have to be under my ajax folder for that to be an issue. However in some web designs that would be an issue. I don't think there's anyway to do this: "folder/../config.php" <-- because folder/ is always in front, the config.php must be under folder/, right?
Joe
The browser has no way of knowing how to decrypt the path. If you look at the source code, you'll only see ajax_script = "ZYAIM315" The PHP script gets the encrypted string and then decrypts it eg. decrypt("ZYAIM315"). If the user knew the "seed" or how to decrypt the string, they could get the name of the included ajax_script, however even with this they need to guess the folder/ name and also, even if they access that path directly it won't do anything since in each ajax script file inside folder/ I require a $variable to be set (from within loader.php) or the script just dies.
Joe
Yeah it might be useless to encrypt/decrypt since people can decrypt the string if they put in some effort... but again, that's extra effort to delay hack attempts and all it takes is a simple encrypt/decrypt to help confuse potential hackers.
Joe
No need to decrypt then, I just pass along the ZYAIM315 in my forged request and you PHP script will see to the rest. (I know this 'ZYAIM315' since it's in th sourcecode from your page.)
MyGGaN
True, it would still load the script matching ZYAIM315. However, it does prevent them knowing that I am targeting an ajax script called "PrintUsernames" for example. Giving potential hackers LESS information is important still. Sure, they may know what the script is doing, but this may help throw off less clever attacks who don't know to look for $.post in the HTML... if they typed "Usernames" it would have had poped up in the HTML, but instead all they'll get is the ZYAIM315 string so they'll find nothing.
Joe
Anyway... the whole point of encrypting the ajax file name that's being posted to, is to add a layer of confusion to as to what the script is doing... personally I use obvious names for my ajax script files. If I want it to load a username, I'll call it LoadUsername.php... I think it's better the HTML says a random string rather than that lol
Joe
Personally I think more layers of confusion is good, but if you don't know exactly what you are doing you might fool yourself into believe that your site is safe. I wish you good luck with your project!
MyGGaN
I am no expert on programming or security haha... I wrote this stackoverflow post up asking for thoughts/help on the subject. After my decision of what to do, nobody has mentioned any security holes yet... except you (thanks for that).I realize they can still get through this. It's not bulletproof at all... which is why I've added several layers of things that need to be = true. If someone wants to abuse my site they could, but they have to be fairly clever. I don't give out extremely sensitive info through ajax anyway. And I can keep an eye on server logs 2.I'll look again 4 more ideas.
Joe
A: 

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.

greenjambi
Disagree, captcha only make sure it's a human. You can send the challenge_id and response via Curl if you like.
MyGGaN
+1  A: 

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.

andreas