How can I better protect my php, jquery, ajax requests from malicious users
I send a lot of data through jquerys getJSON method, an example of a function is
function doSomething(sid){
if(sid){
$.getJSON("ajax/ajaxDoSomething.php",{sid:""+sid+""}, function(data){
//alert(data);
if(data.success == true){
$('#add_vote_div').html('vote received');
$('#list_data_div').html(data.html);
}
else{
$('#add_vote_div').html(data.message);
}
});
}
}`
The problem is tha开发者_JAVA技巧t anyone can look at the source and see that the location of the php file its sending the GET data to, therefore you could just point your browser there and append data to the URL. I do checks on the data to make sure its the right data type, but i dont want users to be able to go to the url at all.
I thought maybe put all the ajax files behind the main document root which would work but jquery can't link to absolute paths like
$.getJSON("var/www/ajax/doSomething.php",{sid:""+sid+""}
(main document root is var/www/html/)
if they made a $.postJSON that would work better, but it doesn't exist, any ideas?
What you need to do is hit a few specific types of attacks. Even for very high-profile sites this is typically enough. And for a site that isn't one of the biggest sites around, these things should be more than enough to stop the script-kiddies.
Cross Site Request Forgery:
Essentially, this is what you are attempting to point out in your initial post. What this kind of attack entails is either, as you are pointing out, figuring out the URL that can enact some user-specific action and calling it directly. Or, and harder to protect against, is done by tricking a logged in user to click a link that leads to that user-specific action.
The first kind can be blocked by tagging each call with the session key and ensuring it is valid. However, this cannot prevent the second.
The good news is this attack can be stopped with a secret value that is part of the url, changes often, is remembered on the backend long enough to ensure it was properly called. We are talking about AJAX here, so the easiest way to do this is to on a full page load, you create a random number secret value. This same is true for traditional forms, bear that in mind and run the check on the old secret value before you create a new one. You hold this value in the session data and append it to all AJAX calls or form submits from the subsequent page. If they match, it is the same user. If not, you just ignore the request.
Each time the user loads a whole new page, create a new secret for that user. This means that only if the attacker IS the user, they will be able to find this value. Which means you've defeated this attack type.
Cross Site Scripting:
XSS attacks are different in that they are the opposite side of CSRF attacks, among other things. This one is easy. Just make sure that ALL data that comes from a user or the database is passed through some function that turns html characters into their entities, like htmlentities()
in PHP, before you display it on your site. What this will do is prevent a user from using JavaScript to redirect users to action links or other malicious things. It will also prevent flash and other objects from being embedded into the page.
Unfortunately, it will also prevent the use of any HTML in comments or the body of articles. This can be skirted with either a VERY strict white list of tags, or some version of alternative code. (such as this site uses)
There really are no good ways to try to create a black list. I've tried. We've all tried. They don't work.
SQL Injection:
I won't go into great detail here, however, suffice to say the above attacks are nothing compared to the damage this can cause. Learn up on it.
Aside from this, there are just some guidelines you should follow. Such as NEVER falling into the trap of believing that the data you sent to javascript will come back how you expect. Assume the worst. This same thing goes for traditional forms. Data sent to the user should be treated, no matter how you encrypted it, as if it is all-new data from the user.
If you have an edit method for a forum post. Check on submit that the user has permission to edit that post. Make sure they are logged in. Make sure the secret matches. Make sure the data they entered is free of SQL injections.
Do these things, and you'll stop the vast majority of attacks.
Not all of them. The attack type that FireSheep uses will still get through, as will any attack like it that targets the users, and not your site. You can protect against FireSheep by using https and not http. But even this does nothing against the various user-targeting attacks. Such as stealing session cookies off their machine, or physical access to their machine.
There is no way to secure data with JavaScript. because all the code in the client side code is available to the attacker. You can try to mask the data connection via complex JSON. but every script kiddie can easily use wireshark and view source and see how the data is generated or where it is sent to.
The solution is to use flash to hash the data. Create a small flash file to receive the data, SALT it and encrypt it with MD5. than sent it to the server. the attacker is able to see the data but it is encrypted.
The attacker can still try to de-compile the flash.
It only raises the bar to hacking very slightly, but you can POST JSON via jQuery.ajax
(that's a link) or jQuery.post
(so's that). jQuery.getJSON
is just a wrapper for ajax
(as are .post
, and .get
). From the getJSON
docs:
This is a shorthand Ajax function, which is equivalent to:
$.ajax({ url: url, dataType: 'json', data: data, success: callback });
Thus, to do your postJSON
concept, you'd just add a type
parameter to it:
$.ajax({
url: url,
type: 'POST', // <== the new bit
dataType: 'json',
data: data,
success: callback
});
If you really wanted to, you could add a postJSON
to the jQuery
object, pre-processing the arguments and then calling $.ajax
. This is basically a copy-and-paste from the jQuery source, but switching .get
to .post
:
if (!jQuery.postJSON) {
jQuery.postJSON = function( url, data, callback ) {
return jQuery.post(url, data, callback, "json");
};
}
Mind you, it's still pretty easy to fake a POST. Not as easy as a GET, but still pretty easy.
to better protect your server from malicious users you need to check the data that come with each request. even if you obfuscate your client code it is always possible to trace where requests are going by using other means. even if you switch to POST requests it is possible to manually create these too.
Have a look at this question for a discussion of a very similar problem. It's really not easy to make it so someone can't pretend to be your JavaScript, as your JavaScript is completely open to the world.
You will want to look at similar methods that are taken to prevent Cross Site Request Forgery (CSRF) attacks. phpsec.org has some good examples that you may be able to adapt for your Ajax requests.
It's actually quite easy to do post requests via ajax, just refer to the generic ajax function of jquery. But that doesn't answer your question as it's almost as easy to fake post requests as it is to fake get requests. There is no way you can reliably hide the server urls that your scripts communicate with. So if that causes any security problems, you have to rethink the security architecture of your website or application.
If these AJAX requests are returning sensitive data, then you would have some form of authentication so that only genuine requests from your application returned data; and anyone just hitting the URL from a third-party website would get an error code.
Hope that helps.
A solution two part method is to send all ajax / json requests to my php files under a redirect psuedo address folder. And to then test the domain of the requests.
yourdomain.com/somePsuedoFolder/?postRequestData....
Then you put a redirect in .htaccess that scans for "somePsuedoFolder" and redirects to your long form php file location. This way what you are asking about, this way people can't see the location of the file on your server.
Of course you still need to deal with people using your Psuedo address to send unwanted requests. However, this way they only have limited information about the folder structure on your server, and there is less likely to be attacks on other files in that location (by random file name target testing ).
What I have done for the same question, transcripted to your example ;
- generate a random number in the PHP controller calling the Javascript; concatenate it to the variable you pass to the Javascript and put it in session, something like :
$randnum = rand(1,100000); $_SESSION['sidrandnum'] = $sid.'-'.$randnum;
in the Javascript, use this new variable to replace your sid
in the data provider, return nothing if the randomized variable is not the same
function dataprovider($sidrandnum) { if ($sidrandnum != $_SESSION('sidrandnum')) return; $sidrandtable = explode ('-', $sidrandnum); $sid = $sidrandtable [0]; ...
This way, the data can be accessed only within the same server execution : you can see the data source, only of what is already shown by the end-user page.
精彩评论