Using HTTP Authentication - php

I am building a REST API in PHP to work with a JavaScript based app. All requests are handled as JSON and some requests require authentication.
An example request would be:
$.ajax({
type: 'GET',
url: 'http://domain.com/api/posts/recent.json',
headers: {
Authorization: 'X-TRUEREST ' + $.param({
username: 'johndoe',
password: '********'
})
},
success: function(response){
// Handle response here (includes auth errors too)
},
error: function(a,b,c) {
}
});
I have based the use of HTTP Authentication headers on the code in this plugin: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L532
As you can see they take passed parameters with the header and then they are used to log a user into the system if they are not already. From what I can tell they expect the auth credentials to be passed WITH the request for data.
An example of this is (note not using CakePHP in my example app):
if ( $loggedIn ) { // logged in is true of false based on session existing
// Then return the JSON as normal
} else {
// Grab HEADERS INFO
$headers = $_SERVER['HTTP_AUTHORIZATION'];
$parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
// Then use the parts to find a user in the DB... and populate $user
if($user){
$this->Auth->login($user); // login the user with our authentication code
// Then return JSON as normal
} else {
print json_encode(array('auth'=>false))
}
}
A few questions that I have though:
Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
Which brings me to the next question...
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?

If you are designing a REST api, you should adhere to REST principles. There are two important ones to highlight for authentication:
Identification of resources through URIs
State transitions through server-supplied links.
To adhere to principle 1, you need to keep your authentication out of your URI. http://example.org/list-of-stuff?auth-token=12345 is not a different resource from http://example.org/list-of-stuff?auth-token=67890, so it should not have a different URI. Having different URIs also makes it impossible to cache the resource across different users.
In general, if the resource would be different depending on some condition, that condition needs to be in the URI. For example, many websites have a /profile url, but what profile you see depends on the invisible "who is logged in" state. This is not RESTful. Instead the url should contain the user, e.g. /profiles/username. Whether you actually get to see that resource depends on whether you are authorized to see it, which depends on whether you are authenticated as a user that is authorized. Authentication is a separate layer from resource identification. (For example, suppose you have an admin user which can see other people's profiles. If you have just a /profile url, how would you architect a method for him to see other profiles? Clearly the presence of a resource is something different from the ability to see it and from who is looking at it.)
So we have established that authentication should not be via parameters in the URI. Since we are using HTTP, we can either provide it in a header, or provide it outside HTTP itself.
Although it's not very common, some REST apis handle authentication at the SSL layer using client certificates. This is great from a technical standpoint, but the user experience is baffling and terrible. Although this article is from 2008, nothing has improved. This approach is also not easily scriptable from browser JS, and even outside the browser it's cumbersome to write an application that has to provide client certificates. Development on the server side is difficult, too, because most web scripting environments do not give you easy access to SSL-layer stuff at all, let alone more esoteric SSL features like client-certificates. Your application may not be able to know what certificate identity was provided with the request.
So that leaves HTTP in the header. We can either use a traditional cookie-based auth, where we "log in" at a special url and get a token back, or HTTP authentication which is natively supported by HTTP.
HTTP authentication is far superior in terms of RESTful principles because it is stateless. (This makes your third question nonsensical--there is no "logged in" or "logged out" state--you either provided the right credentials for the request or you didn't!) You don't need to ensure you first visited a special url and got a magic token you need to save (which might suddenly expire), you just issue a request with your credentials every time. If you are not authorized to access a resource, there's a specific HTTP response code (401) and header (WWW-Authenticate, Authorization) and set of well-defined behaviors. It's also extensible with different authorization methods. There's a fair amount of javascript support too, at least if you stick to XmlHTTPRequest. (Heck, jQuery 1.7.2 even has username and password options, so you don't even need to base64-encode it yourself!)
The downside is that the only HTTP auth methods that are in common use and well supported are Basic and Digest, and both of them are not very secure. They're probably fine if you only use https, but otherwise they are terrible.
Also HTTP auth is useless for normal browser use by humans: no custom login pages, no way to present "forgot password" functionality or other authentication customizations, and still browser makers have provided no easy way to "log out" (i.e., forget the credentials for the current realm)!
Cookie-based auth provides you the most control, but you need to keep server- and client-side authentication state and worry about a whole host of other security issues, such as session fixation or even what constitutes a session! Is it IP address, user agent, some combination? How long should an authenticated session be valid before we expire it? What if there's a proxy involved and the IP address changes frequently? What should we do when the magic token expires? What should we do when the user is not authorized? (You can't use an HTTP 401 response--you need to define your own method specific to your site.) In essence, you need to define your own complex session and authentication protocol or adopt someone else's. At least with HTTP auth, the only thing you need to worry about is an attacker reading your Authenticate headers, and using SSL solves that problem.

Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
HTTP Authentication here appears to be a personal choice of the developer. You could use OpenID. You could use a token. You could use HTTP Header Authentication. You could use sessions/cookies. Heck, you could even use RSA Key Authentication or SSL Client Certificates if you liked.
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
You shouldn't expose the username and password of anything in plaintext, ever (technically you shouldn't even store it as such, but that's not what the question is about). Use a public token with an API, or a unique cookie ID. Personally, I use $_SESSION["id"] to see if a user is logged into anything. Let the AJAX submit and then map the ID to a token internally, if you have to.
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?
I have a function I use for this linked in this answer. You should ideally check for a valid login using a session and setting the value of an index (such as $_SESSION["id"]) to a value that is unique to that account (usually, this is their database ID).
Edit: after reading the comments on the OP, you would have to make sure the session cookie was on any device that was logged in before making the request
Do not take a value: true field to be a login, as this is a security vulnerability.

I think you are mixing (perhaps on purpose) between passing information to the REST api using the URI and authorizing access to the specific server with http simple Authentication.
HTTP authentication can also be used to handle users, but It wouldn't be a very good choice (as elobrated in other answers). users, sessions, security tokens etc should be handled by the app logic while api access can also be safe guarded by the server (with http simple or digest security, NTLM, IP filtering or whatever). letting the web server take some of the security burden/seperating concerns/some kind of testing site/etc'.
an example scenerio is handling http security to protected server access in a Testing zone server, while the app REST api would accept and handle different users, tokens, permission levels etc to everyone who passed the server security checks.
look for this question for more reference

Question 1: Why use the HTTP Authentication and headers? As as far as
I can tell, they are not offering me anything unless I am using them
incorrectly? Why not just pass the username and password in the data
param of the JS?
The query string is part of the URI. The URI is a resource identifier by REST, so it is part of the resource state. The identity, credentials, etc... of the user is part of the client state. Mixing the client state and the resource state by adding client state to the URI would be a violation of the stateless constraint of REST. The data part of other requests, like POST, PUT, DELETE is for describing resource representations, so you should not send auth data with it. Sending headers is the best approach and since HTTP has a dedicated Authorization header, you should use that.
Question 2: As stated earlier I have based my API design on the Cake
plugin above, but from what I can see they ALWAYS pass the username
and password with every request and then decide to use it or not if
the user is logged in. Is this correct? To me, it seems more likely
that authentication and requests for data should be handled
separately. Otherwise I would have to store the username and password
in my JavaScript somewhere so that I can send it with each request.
Your server should authenticate every request, in order to stay stateless. I am not sure about the logic of this lib, I think login is the wrong term to describe what happens, but from REST perspective the implementation details does not matter as long as it uses the HTTP standard properly, and the communication is stateless. The code has changed since you asked your question.
Question 3: How do I know if a user is logged in? I could set a
variable to true and then pass that as part of my JSON with every
request, but can a session work with an external device?
The server does not care whether the client is logged in, since it is client state. If you send a request that requires permissions, then you have to send the data necessary to authenticate the user.

Related

What is your alternative for not using session in REST API in this case

I'm using this method for my API controller:
public function register(Request $request)
{
// Validation Data
$validData = $this->validate($request, [
'user_input' => 'required|regex:/^09\d{9}$/|max:11|min:11',
'user_full_name' => 'nullable|max:20|min:3',
]);
Session::put('user_full_name', $request->user_full_name);
$sms = new SendSms(request()->all()['user_input'],43,request()->all());
$sms->send();
return response([
'data' => 'verification code is sent',
'status' => 200
]);
}
As you can see I have set a session in the method that contains user name:
Session::put('user_full_name', $request->user_full_name);
But this is wrong because I'm not using the benefits of REST API and REST shouldn't come with sessions.
And also I DO need to know the entered user name and get that data for the next steps and that is why I used sessions.
So the question is what is the alternative way of doing this that is suitable & standard in REST API?
Instead of server side sessions we send the session data along with every request. This makes the communication stateless and scalable. As of the techniques, the simplest is sending username and password with every request in an Authorization header. Somewhat more complicated that after the first successful authentication with the username and password, the server sets a different value with for example the user id and signs it with its private key. In the next request the client can send back the user id along with the signature and the server can check with the public key whether it is signed by the private key. You can even separate the signature giving service from the signature checking service. So for example you can do something like auth.example.com and api.example.com and the api.example.com accepts only the signed stuff, but not the username and password. An additional layer is encrypting both the user id and the signature, so it will be harder to copy them and adding an expiration time, so it will be harder to replay the request. Signing each request is the safest, but the most expensive way of doing this. And ofc. you need SSL.
In your upper case there is no user id, because it is registration. In that case just store the entire half filled form in the client. If it doesn't have javascript or some server side language, then maybe inside a cookie and send it back to the server along with the verification code.
Another way of doing this is creating a temporary transaction type of resource on the server with a very long random id and the client can know the id of the resource and it sends back the transaction id along with the verification code. This solution requires server resources, so it is somewhat similar to session management, but it is a good compromise if you struggle keeping the session entirely on the client and when you need eventual consistency, multi tab forms, multi step processes, etc. In the upper case I would rather use the first method unless the verification code goes on a completely different communication channel like SMS, android app, etc. and there is no way or you don't want them to type it to the client manually e.g. to verify they need to click on a link arrived in SMS to their smartphone.
if you are asking for an alternativ you can go with Laravel Passport or sanctum that using JSON Web token (JWT). JWT is common standar for API protection, i'am not going to write some tutorial on how to do that because there are plenty of them.
First Off, I wouldn't recommend using Nullable Data for Verification of any sort. This comes from your validation context, I believe you should make 'user_full_name' => 'required' since you'll be using it for verification.
Secondly, I don't think Session or any alternative is a good way of solving this scenario, I'll rather protect the verification route with the auth middleware, Issue and return a Sanctum API Token
$token = $request->user()->createToken($request->user_full_name);
return response([
'data' => 'verification code is sent',
'token' => $token
'status' => 200
]);
I'll then retrieve the user using the token that'll come as Authorization Header when the user enters the code, then check the code against the sent code for verification. (I'll persist the verification code too).
I just wanted to share a few thoughts on the subject.
Using Sessions, or passing authentication fields in every request is still using sessions, from a strictly "stateless" perspective.
If you are dealing with a process, a series of states where one leads/feeds the next, it's not really a "stateless" process.
However, if you are simply serving resources, then yes perhaps a truly stateless approach is possible.
But no matter how you slice it, a process will require state. The only question is, where it is held, verified and the details on how it gets transported to and from your services.
Cookies, JWT or even URL encoded state are all not stateless, it's just a matter of how you choose to model how that state is transmitted, ingested verified and maintained.
So all that to say, your current solution, is not "wrong", it's just one possible implementation of managing the state of your application between requests.
If your application is running within a browser and not a command line, you automatically get Cookies, Headers and Sessions with every request, so you should feel free to use them.
If however you are using AJAX requests, where you must manually supply/define your headers and maintain Sessions, then yes you may want to model your state using JWT or other methods.
As for how do you maintain an awareness of your users data between request without revalidating their fields, that is exactly what tokens are for.
You then would pass those tokens between requests, then retrieve the fields by referencing the token with any associated records.
You then would manage the life/rate limits of that token in your application server/services.
Anyways, perhaps that is useful, insight.
I'm guessing you need that value for a function that will be baked later from the API (another request), but information is incomplete. If you need that, there are a couple alternatives. One is returning that value to the client, so it can be used on a subsequent API call. Another is storing data in the database with some id or token, and return that id or token in the response so the client can use it in subsequent API calls and you can use that value to retrieve the data from the database.
The second method is better when there is a lot of data that the next API call needs. The first mentor is better for a few data points.

Private authentication algorithm - web security

I'm working on a project which generates audio from text(TTS) and provides player with speed/pitch control to users.
My question is related to request security.
The user got widget_id during registration on my site, he put some js in his site, and api works on his site. When the user click on send button, the api.js file sends ajax POST request to my site with widget_id data as well. Then on my side I got the widget_id and the referer:
$referer = isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : '';
I'm getting the site value related to the widget_id from my database, and comparing it with $referer.
...
if($website_url == $referer) {
$website_checked = true;
}
...
So my question is: can the attacker using some lib(maybe Curl) change the $_SERVER["HTTP_REFERER"] value, and broke my security?
for example if he use curl and the code:
curl_setopt($ch, CURLOPT_REFERER, 'https://anysite.io/');
Thanks.
So I've updated the question cause as I was thinking that can not be trusted. So please the basic steps of Private authentication algorithm...
Update3: So I started a bounty cause I need to understand the algorithm of Private Authentication in my scenario.
Securing Js
When client browser try to access js library, your server should able to save the client info like complete browser name, OS, IP, Device etc. And server should generate a unique ID for that client
Your Js should set cookie in client browser based on unique ID generated
When user click on send button, pass unique ID from cookie. On server side, validate the client details with the details available on server againest unique ID. This is to insure that the POST request is coming from the client who have requested for JS file. A restriction to directly call POST API without initializing JS file
Validating POST request
Add token expiry date
Always check unique ID generation time and Send Button click time and block suspicious API call based on it. (e.g. Time period is too short between ID generation and Send button click / getting POST request on server)
Destroy/Disable unique key once server receive the POST call
Monitor the IPs from which you are receiving the requests. This will help you to identify the robots and disable the server requests for them. A small program will do your work.
No, it is not reliable. Users can (and do) forge them, for example, with Referer Control or RefControl - though, such things are done by the user modifying their own browser.
Most referers are correct (simply because the number of people who'd go to the effort of forging them is small), but if security is an issue, you shouldn't depend on them. For this to be secure, those making requests should include private authentication, to that they can prove they're who they say they are.
So I do not see any activity here.
I think that if I generate random-token on client side, then make ajax request to my server and store the user random-token associated with his widget id, then making another request with same token, and comparing with saved value, will solve my problem!
To perform a secure call you can use JWT encrypted REQUEST, you can read more about JWT security here If you can decode JWT, how are they secure?:
There is a very reliable library to generate this in PHP, you can use generated token in a any client side language such as JavaScript
https://github.com/firebase/php-jwt
For example below example will include a private/public authentication keys, along side your other data which you can validate on your server side, i.e your widget_id in
use \Firebase\JWT\JWT;
$key = "example_key";
$payload = array(
"iss" => "http://example.org",
"aud" => "http://example.com",
"iat" => 1356999524,
"nbf" => 1357000000,
"widget_id" => 123
);
$jwt_public_key = JWT::encode($payload, $key);
You can validate REQUEST with various parameters in payload, and also look into refreshing tokens methods of the library.
Answer to your question is, as other wrote, : no. Referer cannot be trusted and can be tampered easily, or even blocked by browser.
BUT :
Is this a real problem ? Security is always a tradeoff between usability and risk, so you have to measure your risks.
For instance, Google Maps widget security relies on referer. It shows two things IMO :
Google did not find/have anything better to check the widget integration comes from the right place
Even if referer can be tampered... they don't care. It is unlikely to happen but more important : if it happens it is not a big problem (for Google at least, the client who have its Google Maps widget "stolen" won't be happy).
Again, real question is : how sensitive are your widget and your data ?
If you really need security, you will have to implement some private authentication (which is just an other way to say a login) and manage credentials, and a place to store them (a database ?), and handle token exchange, and user will have to log in everytime...
So yes, it is possible to have a real secured widget but as I said it is always a tradeoff, nothing comes for free.

How to secure PHP API from unauthorized AJAX calls (Phonegap mobile app)? [duplicate]

I want to use post to update a database and don't want people doing it manually, i.e., it should only be possible through AJAX in a client. Is there some well known cryptographic trick to use in this scenario?
Say I'm issuing a GET request to insert a new user into my database at site.com/adduser/<userid>. Someone could overpopulate my database by issuing fake requests.
There is no way to avoid forged requests in this case, as the client browser already has everything necessary to make the request; it is only a matter of some debugging for a malicious user to figure out how to make arbitrary requests to your backend, and probably even using your own code to make it easier. You don't need "cryptographic tricks", you need only obfuscation, and that will only make forging a bit inconvenient, but still not impossible.
It can be achieved.
Whenever you render a page which is supposed to make such request. Generate a random token and store it in session (for authenticated user) or database (in case this request is publicly allowed).
and instead of calling site.com/adduser/<userid> call site.com/adduser/<userid>/<token>
whenever you receive such request if the token is valid or not (from session or database)
In case token is correct, process the request and remove used token from session / db
In case token is incorrect, reject the request.
I don't really need to restrict access to the server (although that would be great), I'm looking for a cryptographic trick that would allow the server to know when things are coming from the app and not forged by the user using a sniffed token.
You cannot do this. It's almost one of the fundamental problems with client/server applications. Here's why it doesn't work: Say you had a way for your client app to authenticate itself to the server - whether it's a secret password or some other method. The information that the app needs is necessarily accessible to the app (the password is hidden in there somewhere, or whatever). But because it runs on the user's computer, that means they also have access to this information: All they need is to look at the source, or the binary, or the network traffic between your app and the server, and eventually they will figure out the mechanism by which your app authenticates, and replicate it. Maybe they'll even copy it. Maybe they'll write a clever hack to make your app do the heavy lifting (You can always just send fake user input to the app). But no matter how, they've got all the information required, and there is no way to stop them from having it that wouldn't also stop your app from having it.
Prevent Direct Access To File Called By ajax Function seems to address the question.
You can (among other solutions, I'm sure)...
use session management (log in to create a session);
send a unique key to the client which needs to be returned before it expires (can't
be re-used, and can't be stored for use later on);
and/or set headers as in the linked answer.
But anything can be spoofed if people try hard enough. The only completely secure system is one which no-one can access at all.
This is the same problem as CSRF - and the solution is the same: use a token in the AJAX request which you've perviously stored eslewhere (or can regenerate, e.g. by encrypting the parameters using the sessin id as a key). Chriss Shiflett has some sensible notes on this, and there's an OWASP project for detecting CSRF with PHP
This is some authorization issue: only authorized requests should result in the creation of a new user. So when receiving such a request, your sever needs to check whether it’s from a client that is authorized to create new users.
Now the main issue is how to decide what request is authorized. In most cases, this is done via user roles and/or some ticketing system. With user roles, you’ll have additional problems to solve like user identification and user authentication. But if that is already solved, you can easily map the users onto roles like Alice is an admin and Bob is a regular user and only admins are authorized to create new users.
It works like any other web page: login authentication, check the referrer.
The solution is adding the bold line to ajax requests. Also you should look to basic authentication, this will not be the only protector. You can catch the incomes with these code from your ajax page
Ajax Call
function callit()
{
if(window.XMLHttpRequest){xmlhttp=new XMLHttpRequest();}else{xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState==4&&xmlhttp.status==200){document.getElementById('alp').innerHTML=xmlhttp.responseText;}}
xmlhttp.open("get", "call.asp", true);
**xmlhttp.setRequestHeader("X-Requested-With","XMLHttpRequest");**
xmlhttp.send();
}
PHP/ASP Requested Page Answer
ASP
If Request.ServerVariables("HTTP_X-Requested-With") = "XMLHttpRequest" Then
'Do stuff
Else
'Kill it
End If
PHP
if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) )
{
//Do stuff
} else {
//Kill it
}

How to make sure the API request is made from the certain person who can do that?

I am creating an API for my website which has lots of information, for say, movies. I want to allow certain number of requests. So, for example, 5$ plan allows 10,000 requests a month. User sign ups, gets the API key and then can make a request like
http://website.com/index.php?api_key=API_KEY&movie=Titanic
and the server gives back the answer in json. My question now is, how can I make sure that this API_KEY can be used just by that user? Because if he makes an AJAX request, someone else can see the link with the API_KEY and use it for his project. And I want to allow AJAX requests.
Whoever holds that API_KEY should be considered "that user", so if you want to keep "atomic" requests (where api_key is part of each request, and no request need to depend on previous ones) then you can't really do much about it. But you can try then other approach where you change the way your API works, by getting rid of said "atomicness". In that model it would require any api method to call with session_key instead of the api_key, and your api_key should only be used to generate temporary session_key (kind of login but for API - say login method there). Then all further calls should require session_key login returned. In that case you can control (and limit) the number of sessions created with the single api_key, or i.e. terminate other sessions if new login is called.
Why don't you try sending your API_KEY in custom headers which can be triggered along with php or ajax requests from the client side, that way your API_KEY is not visible in the URL at all, later which can be ripped of from the server using apache_request_headers(), it is a much safer approach, if you are still not satisified you can implement HMAC http authentication, which is damn safe, I bet you.
Approach 1:(without HMAC)
Client Side:
using Jquery
$.ajax({
url: 'foo/bar',
headers: { 'api_key': 'API_KEY' }
});
Using PHP
header('api_key':'API_KEY');
by adding header with the request the URL can be just
http://website.com/index.php?movie=Titanic
On serverside:
$headers = apache_request_headers();
if(isset($headers['api_key']))
{
// validate your api_key from database
}
Approach 2: (with HMAC)
In this case, there is a slight change, instead of sending API_KEY in your url as query string , you will have to send userID or any other unique identifier, inorder which is related to the api_key in your database.
on client side:
do HMAC as given in https://code.google.com/p/crypto-js/#HMAC
or using php function hash_hmac()
using both methods you will get a hashed value which is a combination of your API_KEY , and your data
eg.
$hashed_value = hash_hmac('sha1','titanic','API_KEY');
header('hash':$hashed_value);
your url http://website.com/index.php?movie=Titanic&uid=xx
On server side:
$headers = apache_request_headers();
if(isset($headers['hash']))
{
// then try to recreate your hash in server, like
//using $_GET['uid']= get your API_KEY from DB
$api_key = getApiKey($_GET['uid']);
$hash = hash_hmac('sha1',$_GET['movie'],$api_key);
if($hash==$headers['hash'])
{
// User authenticated
}
}
If you go through HMAC, you can figure out its benefits.
If the API key is made visible on the client in any way, shape or form, users who visit that page can also make requests on the API user's behalf, as long as they are "power user" enough to inspect the code and/or HTTP requets. Regardless of whether you have encryption, whether you accept the key in the URL, cookie or whatever... Those other methods may be a slight inconvinience, but a user that knows enough to start searching for the API key is likely also knowedable enough to have heard about Fiddler and the like.
This is the very reason why APIs typically don't make themselves available to JavaScript (i.e. AJAX), but only to direct requests - the server will be the one making the request, and thus it wouldn't need to reveal their API key to its users that way.
There's simply no solution to this, short of not allowing AJAX to use the API. The only kind of an API you should allow AJAX access to is a publically available API (as in "no login required"), limited only by IP making N amount of requests in N amount of time instead.
It's not possible using just (effectively public) API keys. What you need is cryptographic authentication with secret keys. TLS with client side certificates ought to do it.
Perhaps not a 100% perfect solution but for your particular movie business example it should work out just fine.
First you give each user a username and password.
In order to make an AJAX call user will have to specify 3 things:
username
desired movie id
API_KEY
Now, the API_KEY will be a hash (you can use sha1() or md5() or even a combination of them) that is generated based on:
user's password
desired movie id
today's date
So here's approximately what user will have to do in order to make an AJAX request:
$username = 'john_smith';
$password = 'abc';
$movie_id = 'Titanic';
$date = date('Y-m-d');
$API_KEY = sha1($password . $movie_id . $date);
AJAX("http://website.com/index.php?user=$user_name&movie=$movie_id&api_key=$API_KEY");
(Similar can be done in JavaScript in case you are expecting users to only have client side environment.)
On your side you will have to do as follows. Knowing the username you find out their password in the database. Get the movie_id from the request. And today's date we all know. (You can also check for yesterday and tomorrow to avoid time-zone issues.)
Then you generate the same hash and compare it to the API_KEY that user sent you. If they match - all good.
This way you will end up with unique AJAX calls that are valid for one movie only and will expire in about a day.
I think that would be a pretty efficient approach, at least business-wise.
instead of having all the data in the url, why not use the POST method, and have all the data sent behind the scenes. you could then post their id and other data between pages (using hidden fields) or using a session.
You can pull cookies in a web service. The web server then can use the authentication cookie to authenticate the web service call. I'm sure what ever frame work your using has an authentication token stored in a cookie on the browser somewhere and there's a snipet of php somewhere to authenticate it.
Danger not a php example here.
I have an authenticated web service on my web site http://www.gosylvester.com that just returns a hello world but if you put a trace on it and sign in. You'll see the authentication cookie go up and down with it.
Your welcome to play around with the web service. There's a button on the main page that says "ASP authenticated Test Button It says hello unless you are signed in" put a trace on your browser and click it.
user guest password abc123$
You can also log in via webservice on my site but that's another post
Good Luck
If you really want it secure, use Oauth authentication (2-legged variant, for your case). Of course, you could also use HMAC authentication, or key exchange, as other authors suggested, but it's always a better idea to use existing and verified protocols, not invent your own.
See:
Securing REST APIs
Using Oauth to protect internal REST API

Why does livehttpheaders show my login and password and how can I prevent it?

I was looking at the livehttpheaders plugin for Firefox and decided to test my login page. I noticed that the parameters shown inside of it contain my login and password. For example:
username=sarmenhb&password=thepassword&submit=Login
in plain English.
I don not see this on other sites.
What can I be doing wrong? I see this as a security flaw. The login page, all it does is validate and log in the user. All fields are ran through mysql_real_escape_string (in case that is relevant).
The information has to get to the server from the client some how. Use SSL if you are worried about security.
Even if you do an MD5 hash in Javascript, this does not help because it is trivial to submit the hash to the login page, and the hash effectively becomes the password. All things are plain text until they, or the transport, is encrypted. POST the variables, use SSL.
To add from my comment below. You may not see the headers for other-sites because they may use AJAX, POST method or another client-side mechanism to authenticate.
This reminds me of a certain building in a large city (I am sure there are others in other places) where they have a web based interface to the building concierge. Residents can log on to a web site (over http) and specify (among other things) who is allowed to enter their apartment for repairs etc in their absence. I am sure the whole thing was programmed by someone's nephew who is a 'guru'.
I am sure it is, shall we say, good enough.
You're seeing it for your site and not for others because livehttpheaders shows the URL for GET requests, but doesn't show the content for POST requests.
Sending login information through GET requests is a minor extra security hole over sending them POST, in that the URLs for GET requests are often logged in various places, whereas almost no one logs POST content. Does everyone with permission to look at the webserver logs have permission to know the CEO's password?
However, as others have pointed out, unless you're using https: for login, data is going across the network in plain text whether you use GET or POST. This is almost always bad.
Still, as an intermediate measure I would change your app to send username and password stuff as a POST, not a GET, so that you don't end up storing usernames and passwords in your webserver logs - it's no use using https over the wire if you're doing something that then writes the username and password to an insufficiently protected logfile on the server.
When you are using http and submit a form, the form contents are sent across the wire "in the clear", as you're seeing. When that form submission includes credentials, then yes, you have a security issue.
Among your alternatives are:
Use https, so that over-the-wire communication is encrypted
Use OpenID for login, which pushes management of https credentials off onto the user's OpenID provider
Use Javascript on the client side to encrypt the credentials before posting the form
The latter approach tends to get people into trouble if they're not very careful, because the mechanism for encrypting the credentials is fully visible to anyone who cares to inspect the javascript.
HTTP live header shows POST requests as well. Post sends the data the same way as GET does but the only difference being that the variables are passed in the url itself in GET but in POST they are appended to the HTTP header.
To get better security use encrypting in JS (only password or token+password). But that still can be hacked using rainbow tables for say MD5 or any other hashing technique.
SSL is the only way to achieve high security.

Categories