PHP Development
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me

The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.

Go Back   Dev Shed ForumsProgramming LanguagesPHP Development

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old October 29th, 2012, 04:49 PM
Moderns Moderns is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2010
Posts: 53 Moderns Negative: is most likely a SPAMMER and a traitor to the cause. 
Time spent in forums: 9 h 21 m 50 sec
Reputation Power: 0
Exclamation 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.

Reply With Quote
  #2  
Old October 29th, 2012, 05:04 PM
requinix's Avatar
requinix requinix is offline
Still alive
Dev Shed God 16th Plane (12500 - 12999 posts)
 
Join Date: Mar 2007
Location: Washington, USA
Posts: 12,877 requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)requinix User rank is General 120th Grade (Above 100000 Reputation Level)  Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1Folding Points: 417516 Folding Title: Super Ultimate Folder - Level 1
Time spent in forums: 5 Months 1 Week 5 Days 7 h 59 m 22 sec
Reputation Power: 8977
Send a message via AIM to requinix Send a message via MSN to requinix Send a message via Yahoo to requinix Send a message via Google Talk to 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.

Reply With Quote
  #3  
Old October 29th, 2012, 05:12 PM
Moderns Moderns is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2010
Posts: 53 Moderns Negative: is most likely a SPAMMER and a traitor to the cause. 
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.

Reply With Quote
  #4  
Old October 29th, 2012, 05:16 PM
Moderns Moderns is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2010
Posts: 53 Moderns Negative: is most likely a SPAMMER and a traitor to the cause. 
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.

Reply With Quote
  #5  
Old October 30th, 2012, 10:47 PM
E-Oreo's Avatar
E-Oreo E-Oreo is offline
Lost in code
Dev Shed God 7th Plane (8000 - 8499 posts)
 
Join Date: Dec 2004
Posts: 8,063 E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)  Folding Points: 945 Folding Title: Novice Folder
Time spent in forums: 2 Months 1 Day 6 h 49 m 31 sec
Reputation Power: 7104
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.
__________________
PHP FAQ
How to program a basic, secure login system using PHP
Connect with me on LinkedIn


Quote:
Originally Posted by Spad
Ah USB, the only rectangular connector where you have to make 3 attempts before you get it the right way around

Last edited by E-Oreo : October 30th, 2012 at 10:51 PM.

Reply With Quote
  #6  
Old October 31st, 2012, 03:44 AM
Moderns Moderns is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2010
Posts: 53 Moderns Negative: is most likely a SPAMMER and a traitor to the cause. 
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.

Reply With Quote
  #7  
Old October 31st, 2012, 07:34 PM
E-Oreo's Avatar
E-Oreo E-Oreo is offline
Lost in code
Dev Shed God 7th Plane (8000 - 8499 posts)
 
Join Date: Dec 2004
Posts: 8,063 E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)E-Oreo User rank is General 92nd Grade (Above 100000 Reputation Level)  Folding Points: 945 Folding Title: Novice Folder
Time spent in forums: 2 Months 1 Day 6 h 49 m 31 sec
Reputation Power: 7104
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.

Reply With Quote
  #8  
Old November 1st, 2012, 08:38 AM
Moderns Moderns is offline
Registered User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Mar 2010
Posts: 53 Moderns Negative: is most likely a SPAMMER and a traitor to the cause. 
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.

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming LanguagesPHP Development > How to protect AJAX file on server that is called from API output?

Developer Shed Advertisers and Affiliates



Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap