The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.
|
 |
|
Dev Shed Forums
> Programming Languages
> PHP Development
|
How to protect AJAX file on server that is called from API output?
Discuss How to protect AJAX file on server that is called from API output? in the PHP Development forum on Dev Shed. How to protect AJAX file on server that is called from API output? PHP Development forum discussing coding practices, tips on PHP, and other PHP-related topics. PHP is an open source scripting language that has taken the web development industry by storm.
|
|
 |
|
|
|
|

Dev Shed Forums Sponsor:
|
|
|

October 29th, 2012, 04:49 PM
|
|
Registered User
|
|
Join Date: Mar 2010
Posts: 53
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
|
|
How to protect AJAX file on server that is called from API output?
Hello,
I am integrating my API's to other sites. To make it easier to understand: Let us say my main site which produces API's is www.main.com
Another site (www.apiUser.com) will need to use my main site API. I am adding the below code in the index page of it (www.apiUser.com/index.php)
$showApi = file('http://main/api.php?apiId=44');
foreach ($showApi as $output){
echo $output;
}
Now, on the html comes from the page: http://main/api.php, I trigger Javascript event to reach AJAX page on server which is : http://main/ajax.php
Users will set values through the javascript when they click on the link, they will get directed to the ajax.php as below:
button.onclick=function(){
callAjax("http://main/ajax.php","x=5&y=9");
};
Now, the above function, will call the page: "ajax.php" as request: ajax.php?x=5&y=9
My question! How can I protect the page ajax.php from browser bar setting values? I need users to only access the page through the javascript (html in the API html we got from the server). Someusers can enter the link in browser and set values in database as much as they need: http://main/ajax.php?x=10000&y=98989!! They will corrupt my database in this way. I even need to restrict the client of the API from direct access as well!! Just through the Javascript to be accessed!
I tried to generate md5(uniqid()) and to add it to session in the output of api (inside http://main/api.php) which is viewed on the site: www.apiUser.com, but the problem the session does not work on the http://main/ajax.php  It seems different sessions! I added this variable to hidden html input and wanted to compare between the session on ajax.php and the hidden input value but the sessoin did not work! I tried session_start() on the top of page http://main/ajax.php but does not work! Also added it on top of http://main/api.php!
Anyhow! I need to find any way to protect unauthorized access to the page http://main/ajax.php! Specially we are getting API's from http://main/api.php and send it to client site (www.apiUser.com)... Using $_SERVER['http_referer'] might not work as I am not controlling inputs from the site www.apiUser.com
Any good solution? Will be so thankful!
Thanks a lot for your help! Appreciate.
|

October 29th, 2012, 05:04 PM
|
 |
Still alive
|
|
Join Date: Mar 2007
Location: Washington, USA
|
|
|
1. Require credentials so you can track who is sending what
2. Require a signature of the request: essentially a hash of some private information and the request itself
3. Don't make people use the API client-side (eg, in AJAX) unless it's absolutely necessary. Protip: it probably isn't.
|

October 29th, 2012, 05:12 PM
|
|
Registered User
|
|
Join Date: Mar 2010
Posts: 53
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
|
|
Quote: | Originally Posted by requinix 1. Require credentials so you can track who is sending what
2. Require a signature of the request: essentially a hash of some private information and the request itself
3. Don't make people use the API client-side (eg, in AJAX) unless it's absolutely necessary. Protip: it probably isn't. |
Thanks for your response. Please could you clarify?
1. Require credentials so you can track who is sending what
My site does not apply user login (api clients login). Whenever any client generates new API to be pasted on his site, then a security number will be generated to access the API. So the AJAX calls will be without authorizations
2. Require a signature of the request: essentially a hash of some private information and the request itself:::
Could you please give me a simple example? I never did that. Will it solve the problem 100%?
3. Don't make people use the API client-side (eg, in AJAX) unless it's absolutely necessary. Protip: it probably isn't.
As I know, the only ways to submit requests to servers are the forms and the AJAX. Is there any alternate way? I am in need to send information from the www.userApi.com page to my ajax page (http://main/ajax.php).
Thanks a lot.
|

October 29th, 2012, 05:16 PM
|
|
Registered User
|
|
Join Date: Mar 2010
Posts: 53
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
|
|
To make things easier to understand.
Clients get tokens to request the API from the Server.
Users world wide will access clients website API and click on a button located on the API HTML to go to my server AJAX page (http://main/ajax.php).
So, just I need to protect my ajax.php page from clients and world wide users
Thanks a lot.
|

October 30th, 2012, 10:47 PM
|
 |
Lost in code
|
|
|
|
Quote: | It seems different sessions! |
Sessions use cookies to track the session ID, so they won't work across domains either.
Quote: | Using $_SERVER['http_referer'] |
Using the http referer for authentication is never a good idea.
Quote: | I even need to restrict the client of the API from direct access as well!! Just through the Javascript to be accessed! |
This type of restriction is impossible to implement.
Quote: | As I know, the only ways to submit requests to servers are the forms and the AJAX. Is there any alternate way? |
No other way.
Quote: | 3. Don't make people use the API client-side (eg, in AJAX) unless it's absolutely necessary. Protip: it probably isn't. |
Based on the OP's other recent posts, I think it probably is necessary in this case.
Quote: | 2. Require a signature of the request: essentially a hash of some private information and the request itself |
This is probably what you need to do. This assumes that:
* the values (ex: x and y) are being generated by one server (serverOrig)
* the values are being sent from serverOrig to the client
* the values are then being sent from the client to serverTerm (a second server)
* you need serverTerm to be able to verify that the values are coming from serverOrig and were not changed by the user
Start by defining a secret key. This needs to be shared on both servers. It should never be sent to a client.
PHP Code:
$secret_key = "xckjpZXlkcjposSRA82i3jpaju0s98das90duskjkasDJPOAIdjkw";
To "sign" a message, you compute a hash of the secret key plus the message. This is performed server-side on serverOrig.
PHP Code:
$message = "x:1235;y:84534";
$hash = hash('sha256', $message . $secret_key);
The message and hash are then sent to the client. Now, the client transmits both values to serverTerm:
Code:
http://serverTerm/api.php?hash=660b764423f30cb04ce334a0bb4fde3e1f0272d56231022249098ab9804d771f&message=x:1235;y:84534
To validate the message, serverTerm re-computes the original hash using the secret key and compares it to the hash sent by the client:
PHP Code:
$message = $_GET['message'];
$hash = $_GET['hash'];
$check_hash = hash('sha256', $message . $secret_key);
if($hash === $check_hash) {
die("Message validated!");
} else {
die("Message was modified");
}
If the two hashes are equal, then you know that the user did not modify message at all.
Obviously, you can sign and validate the API response in exactly the same manner as well.
Note though that this does not prevent the user from sending the signed API request more than once if they want to; If you need to prevent that, then you need to add something called a nonce to it as well.
Last edited by E-Oreo : October 30th, 2012 at 10:51 PM.
|

October 31st, 2012, 03:44 AM
|
|
Registered User
|
|
Join Date: Mar 2010
Posts: 53
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
|
|
Quote: | Originally Posted by E-Oreo Sessions use cookies to track the session ID, so they won't work across domains either.
Using the http referer for authentication is never a good idea.
This type of restriction is impossible to implement.
No other way.
Based on the OP's other recent posts, I think it probably is necessary in this case.
This is probably what you need to do. This assumes that:
* the values (ex: x and y) are being generated by one server (serverOrig)
* the values are being sent from serverOrig to the client
* the values are then being sent from the client to serverTerm (a second server)
* you need serverTerm to be able to verify that the values are coming from serverOrig and were not changed by the user
Start by defining a secret key. This needs to be shared on both servers. It should never be sent to a client.
PHP Code:
$secret_key = "xckjpZXlkcjposSRA82i3jpaju0s98das90duskjkasDJPOAIdjkw";
To "sign" a message, you compute a hash of the secret key plus the message. This is performed server-side on serverOrig.
PHP Code:
$message = "x:1235;y:84534";
$hash = hash('sha256', $message . $secret_key);
The message and hash are then sent to the client. Now, the client transmits both values to serverTerm:
Code:
http://serverTerm/api.php?hash=660b764423f30cb04ce334a0bb4fde3e1f0272d56231022249098ab9804d771f&message=x:1235;y:84534
To validate the message, serverTerm re-computes the original hash using the secret key and compares it to the hash sent by the client:
PHP Code:
$message = $_GET['message'];
$hash = $_GET['hash'];
$check_hash = hash('sha256', $message . $secret_key);
if($hash === $check_hash) {
die("Message validated!");
} else {
die("Message was modified");
}
If the two hashes are equal, then you know that the user did not modify message at all.
Obviously, you can sign and validate the API response in exactly the same manner as well.
Note though that this does not prevent the user from sending the signed API request more than once if they want to; If you need to prevent that, then you need to add something called a nonce to it as well. |
Dear E-Oreo,
Thanks for your kind response and your effort.
Actually I have voting system, I need users to use the (mouse click) to vote ONCE from each machine and the "Javascript" cookies will prevent them from voting same time to same option. I do not want users to use the browser address bar to vote  there was no way to use the PHP cookies as we have different domains as you know!
Your solution is working out in case of messaging system, but in case of voting system, users simply can enter in the browser this link: http://serverTerm/api.php?hash=660b764423f30cb04ce334a0bb4fde3e1f0272d56231022249098ab9804d771f&message=x:1235;y:84534&votingOption=2,, as users will be able to see the hash when it is getting sent to html from server.
Users can vote million times!! While each user has to vote 1 time from each machine (according to cookies).
So how can I prevent from voting from the browser address bar based on what I mentioned before?
Note: I am using anonymous voting, I do not have user accounts to get signed in into the system. Just cookies as an identifier for the person who votes. I have no problem if they delete their cookies and vote again! Just I do not need them to use the browser address bar and enter the AJAX link and vote!
Thanks a lot.
|

October 31st, 2012, 07:34 PM
|
 |
Lost in code
|
|
|
|
As I mentioned, if you don't want the user to be able to re-send the API request more than once then you just need to implement a nonce.
A nonce is simple a random value that you only allow to be used once. Used nonces are stored in a database table. The nonce is included in the hash for validation purposes.
PHP Code:
$secret_key = "xckjpZXlkcjposSRA82i3jpaju0s98das90duskjkasDJPOAIdjkw";
$nonce = hash('sha256', crypt(microtime(true))); // this just generates a random string
$message = "x:1235;y:84534";
$hash = hash('sha256', $message . $nonce . $secret_key);
Then the AJAX request is sent to:
PHP Code:
"http://serverTerm/api.php?message={$message}&nonce={$nonce}&hash={$hash}"
Now on the check side, you just need to perform some additional database steps:
PHP Code:
$message = $_GET['message'];
$hash = $_GET['hash'];
$nonce = $_GET['nonce'];
$check_hash = hash('sha256', $message . $nonce . $secret_key);
if($hash === $check_hash) {
if(check database table to see if $nonce already exists in it)
{
die("Nonce already used, request denied");
}
else
{
insert nonce into database table
die("API request successful");
}
} else {
die("Message was modified");
}
Now it is only possible for the user to visit each signed URL once.
However, for a simple voting system this isn't needed if you use JavaScript to cast the vote. For example, to vote you could use the JavaScript code:
Code:
// jQuery
$('body').append('<script src="http://mainSite.com/vote.php?votingOption=2" type="text/javascript"></script>');
You would use this same voting code on mainSite.com and all of your sub sites. All of them would just submit the vote to mainSite.com/vote.php. Because vote.php is located on mainSite.com, it will be able to access the user's mainSite.com cookies and can use one of them to track voting status. There is no need to have a separate cookie on each site.
|

November 1st, 2012, 08:38 AM
|
|
Registered User
|
|
Join Date: Mar 2010
Posts: 53
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
|
|
As I mentioned, if you don't want the user to be able to re-send the API request more than once then you just need to implement a nonce.
A nonce is simple a random value that you only allow to be used once. Used nonces are stored in a database table. The nonce is included in the hash for validation purposes.
PHP Code:
$secret_key = "xckjpZXlkcjposSRA82i3jpaju0s98das90duskjkasDJPOAIdjkw";
$nonce = hash('sha256', crypt(microtime(true))); // this just generates a random string
$message = "x:1235;y:84534";
$hash = hash('sha256', $message . $nonce . $secret_key);
Then the AJAX request is sent to:
PHP Code:
"http://serverTerm/api.php?message={$message}&nonce={$nonce}&hash={$hash}"
Now on the check side, you just need to perform some additional database steps:
PHP Code:
$message = $_GET['message'];
$hash = $_GET['hash'];
$nonce = $_GET['nonce'];
$check_hash = hash('sha256', $message . $nonce . $secret_key);
if($hash === $check_hash) {
if(check database table to see if $nonce already exists in it)
{
die("Nonce already used, request denied");
}
else
{
insert nonce into database table
die("API request successful");
}
} else {
die("Message was modified");
}
Now it is only possible for the user to visit each signed URL once.
However, for a simple voting system this isn't needed if you use JavaScript to cast the vote. For example, to vote you could use the JavaScript code:
Quote: | Originally Posted by E-Oreo
Code:
// jQuery
$('body').append('<script src="http://mainSite.com/vote.php?votingOption=2" type="text/javascript"></script>');
You would use this same voting code on mainSite.com and all of your sub sites. All of them would just submit the vote to mainSite.com/vote.php. Because vote.php is located on mainSite.com, it will be able to access the user's mainSite.com cookies and can use one of them to track voting status. There is no need to have a separate cookie on each site. |
Hi man, thanks for your nice answers always.
Actually I am unable to get the best understand from the quoted text above  I will explain to you my problem.
1. Clients are getting html output (API) into their sites using function file of PHP as I mentioned above, clients let us say like: www.dell.com, www.HP.com, www.bmw.com
2. When users world wide access clients websites (dell,hp,bmw), they will access the API generated by my main site which has the link: www.mainSite.com/api.php?apiId=44
3. Users world wide will vote on (dell, hp, bmw, ..) sites. Their voting will go to the link: www.mainSite.com/vote.php?votingOption=2
4. In the file www.mainSite.com/vote.php, cookies is not working at all! If you try to set cookies million times you will get EMPTY (var_dump($_COOKIE)) is EMPTY always! While cookies works fine on (dell,hp,bmw) sites..
As you mentioned: they will be able to use same cookies on www.mainSite.com, but honestly I tried it many times and unable to set cookies there  why? I need central cookies to track.
Also, I do not need any body to access the page: www.mainSite.com/vote.php from browser address bar AT ALL, voting should be done by javascript clicks, it is not a matter of nonce because nonce will allow them to access the page once from browser address bar and then will disallow them.
I hope you can understand my problem.
Thanks a lot.
|
Developer Shed Advertisers and Affiliates
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|