I would like to create a website and app where users can search a song and collect it into a public list (saved to a database). Therefore, I would not like to let the user authenticate himself just to add 1 song to the list. Because you need to provide a token in order to search, I've found several options:
I will save the token into the database (refresh every hour using a CRON job), and when the user wants to search, I will retrieve the code and append it client side so the request will be successful. This, of course, exposes the token, even though it can only search, it is not really safe. PHP is no option, as it has to be a website and an app
I need to let everyone log in which is very annoying
I need to make a PHP script that will receive some endpoints from the client side and will execute it server side and send the response back. This, however, does not scale really well when there are a lot of users and the rate-limiting from one IP will soon be activated.
Are there any other options I can try?
EDIT:
The songs should be searched by calling the Spotify API, not everyone has Spotify, therefore I was thinking about one token that could be shared
Less annoying but not secure:
Mobile App
First time the app is used:
Require authentication and capture the device UUID.
Store the device UUID in the database which is related to the authenticated user and also related to the user's play list.
Next time the app is used the device UUID already exists in the database so assume the related play list is the one to use.
Browser
First time the page (or after clearing cookies) is used:
Require authentication and set a long-lived cookie.
Store the cookie in the database which is related to the authenticated user and also related to the user's play list.
Next time the page is used the cookie will already exist so assume the related play list is the one to use.
If you're looking to use OAuth as a means of TLS between the server and client then each user must authenticate against the server with a request of information.
Since, I assume, this is not a public API (for anyone to access data), you only want your client app to be able to authorise such requests.
In this case, you would not need to send a 'scope' to the authentication server, simply just generate a resource token but FORCE the user to login.
Using that resource token, the client will send a second request to the resource server. Inside this request should hold the ACTION and DATA for that request and on receipt should then delete that token from the database. There is no need for a CRON job.
Client -> Authentication Server
<- Resource Token (OK)
<- Status BAD
Client -> Resource Server { Resource Token, Action, Data }
<- Status OK
<- Status BAD
Check the token exists and "in-date"
Check that the action is permitted
Check that the data is more than 1 song
Execute the insert, remove the token and return a response header
The reason you do not need a CRON job is because you should set a timeout for the token. For example, add a (TIMESTAMP) created DEFAULT CURRENT_TIMESTAMP to the database, pull the row out of the database for that token and ensure that it wasn't created n minutes ago, if it was then its void (expired) and can no longer be used.
Here is a URI example for the resource server:
/api/resource_token/action?data=
Of course, data should be a POST parameter but, for this, it was easier to show it as a GET request. It doesn't need to hold ALL the data, it could be anything like:
?song=[{"artist": "foo", "song": "bar"}]&type="json"
Using AltoRouter it would look something like this:
$router->map('GET|POST', '/api/[*:token]/[*:action]', function($resourceToken, $requestAction) {
foreach(array('Song', 'Type', 'PlaylistId') as $param)
if(!isset($_POST[$param]))
die(...Return your response header error...);
if(($token = SomeModel::getToken($resourceToken))->isValid())
SomeController->using($token)->execute($requestAction);
die(...Return your response header success...);
}, 'API');
Related
Our android app only has facebook login.
Here's what happens in server:
A user is created when a POST request is sent using facebook's user access token in body.
Whenever a user gets created via POST request, an api token is generated and sent as a response as follows:
{"message":"User Successfully Created","api_token":"ACITyBKf0jKrfqOFumTMcaEEJ8jU151crRdESMPmBj8zbeENslULHfNXlKeo"}
I did this because the api token that is generated in the server is stored in android app's local storage and is needed to make other requests.
Now, if the user already exists in the server, the response would be
{"message":"User Already Exists!!","api_token":"ACITyBKf0jKrfqOFumTMcaEEJ8jU151crRdESMPmBj8zbeENslULHfNXlKeo"}
This is in case the user deletes the app and installs again.
Now, to submit score, a PATCH request is to be sent with:
Headers:
Content-Type:application/x-www-form-urlencoded
api_token:ACITyBKf0jKrfqOFumTMcaEEJ8jU151crRdESMPmBj8zbeENslULHfNXlKeo
fb_id:xxxxxxxxxx
Body:
distance:2
golds:19
xp:23
(Note: I tested the above request using postman)
Now, the problem is that I spotted a loophole.
A person can find out their facebook user access token and their facebook id anytime. So, if they make a POST request with that user access token, they will receive the api_token (In the "User Already Exists!!" response). And once they have api_token and fb_id, they can make a PATCH request to modify their scores to whatever they want.
What am I doing wrong? How can I secure my server from being hacked like this?
Please help me. I am a beginner in api design.
Thanks
If their API token is available to them in the app at all, that's probably a bad thing. If its not available to them in the app, say they're just forging in-app POST requests and retrieving the raw data, then they're probably trying to hack or pentest the system.
If that's the case, maybe sending the unencrypted API key via POST in the first place is a bad idea. If their API key is all they need to start doing bad things to your system, why ever give it to them in the first place?
Because your app needs it to remember them. What about something like this:
New user, server md5 hashes their API key and sends it to them to be stored.
Existing user, server md5 hashes their api key and sends it to them to be stored (if needed)
Official Existing Score change occurs: app re-md5 hashes the already hashed api key, sends that with the PATCH request. Server has database with doubly hashed api keys which it finds yours and identifies you as the user, and things go on normally from there.
My app is simple, it connects to the Google+ API to authenticate the user, and if successful, it retrieves the user's email and then performs a series of operations on a given database based on the email retrieved.
My main issue is that every hour, my access token expires, and I seem not to know how to "refresh" it. I get the following error, which I imagine is expected:
The OAuth 2.0 access token has expired, and a refresh token is not available.
I am currently storing the access token on a database, and I can therefore retrieve if needed. My only question is how do I use that token to gain a new one?
Whoa, it took me significantly longer to figure this out, and the answers out there seemed quite incomplete to me.
Before we start please keep in mind that this answer assumes you are using the latest Google API PHP Library, as of May 26th of 2014.
1 - Make sure the access type your app requests is offline. A refresh_token is not provided otherwise. From Google: This field is only present if access_type=offline is included in the authorization code request.
$gClient->setAccessType('offline');
2 - Upon the first authorization, persist the provided refresh_token for further access. This can be done via cookies, database, etc. I chose to store in on a database:
$tokens = json_decode($gClient->getAccessToken()); /* Get a JSON object */
setRefreshToken($con, $tokens->refresh_token /* Retrieve form JSON object */);
3 - Check if the AccessToken has expired, and request a refreshed token from Google if such is the case.
if ($gClient->isAccessTokenExpired()) {
$refreshToken = getRefreshToken($con, $email);
$gClient->refreshToken($refreshToken);
}
Where getRefreshToken is retrieving the previously stored refresh_token from our database, and then we pass that value to the Client's refreshToken method.
Quick Note: It's key to remember that if you had previously authorized your app, you probably won't see a refresh_token on the response, since it is only provided the first time we call authenticate. Therefore, you can either go to https://www.google.com/settings/security and Revoke Access to your app or you can add the following line when creating the Client object:
$gClient->setApprovalPrompt('force');
From Google: If the value is force, then the user sees a consent page even if they previously gave consent to your application for a given set of scopes. Which in turn ensures that a refresh_token is provided on each authorization.
Full Sample Here: http://pastebin.com/jA9sBNTk
I'm writing a RESTful Webservice with the Slim Microframework and use GET for reading data from a mysql database (select query) and also POST/PUT/DELETE for insert/update/delete rows in the database.
My question is now, is this not a big security issue if everybody is able to write or delete data in the database? But how could I prevent this, I thought the ST in REST stands for state transfer (so the webservice is stateless), which is a contradiction to a state like being logged in or not. And if I would pass some login data with the client which is allowed to write in the database, couldn't a bad guy catch the logindata and fake requests with it and for example delete all entries?
So, whats the normal way to go with this, the only Slim Framework examples I had found always show the route examples, but not how to secure it.
Are there also some opportunities in the Slim Framework to implement this what I need? It should be as easy as possible and the request should be responded nearly as quick as without an authentification or similar. There are no sensitive data like passwords, for me it would be enough that not everybody with a cURL commandline tool can delete all rows or things like that.
Would be great if anybody could explain me what to do and/or give some examples. I also need to know, what I maybe will need to change at the clients which are allowed to send the requests.
Lots of thanks.
Each request has to be authenticated and authorised.
People often get tied up with the word 'stateless'. This really just means that from one request to the next, the RESTful service has no prior knowledge of the users state.
BUT, the service is obviously allowed to be aware of the authenticated user that has just made a request, else how would it decide if it should allow access?
Therefore, you can 'store' the authenticated user in some variable during each request. Then it's up to you how you use this information to authorize the request.
I like to keep it simple and have all my users as a resource in my URI chain. They make requests like users/{username}/someresource.
I authenticate using http basic authentication (over SSL) and authorise based on the URI. If the request failed authentication, its a 401 Unauthorized Request. If the URI {username} and authenticated {username} do not match, the request is a 403 forbidden. If it is authenticated and authorized, the request is allowed (http code dependant on http verb)
Now that's the web service covered, now on to the web service client. This of course HAS to store state, otherwise your user would have to log in every time they make a request.
You simply store the users session in the application (as per normal session management) with the addition that you store the username and password (encrypted of course) in the session. Now every time a request is made, your web service client needs to retrieve the username and password, and send it with the request to your web service.
It will be stateless, in the sense that there won't be a session or a cookie, really. You'd normally issue out a key that would be required for INSERT/UPDATE/DELETE.
It is then up to you to pass the key with each request and to determine when a key should expire.
It would be as safe as normal http authenticated sessions. These use a cookie etc to authenticate the connected user to the stored session state.
A stateless service would be no different - the token is passed to the service just as a token is stored in a cookie for normal http. If you are worried about sniffing (IE man in the middle attacks) you would secure the link via SSL.
The authentication token generated by the service would be encrypted and would include a salt which is also verified on the server for each request. You could also limit the session time to suit your paranoia, and also check changes in source IP, user agent etc and expire the user's token if these change.
I recently ran into similar problem. As recommended by people here, I have decided to go with OAuth Authentication.
I am using HybridAuth A php wrapper for OAuth and out of the box sign in solution for Facebook, Twitter, Google, LinkedIn, etc.
I going to build a system which have 2 part:
1. PHP Website (CakePHP).
2. Mobile application (Android & iPhone).
User must login with usr&pwd to use my system(web and mobile application). But i don't have a lot experiences with user authentication. What should i store: usr&pwd, token string. I want to find an "user authentication model" for my system (Web and Mobile application).
Is there anybody have experience about user authentication. Anybody know how to implement this?
This is what we do for our applications,
First we send a username and a password to the server from our application.
At the server, they authenticate the credentials and return a response which is combination of a request token and sucess flag.
In our applicatoin, we check the sucess flag. If its set to true, we save the request token and use it for all the next outgoing requests to the server.
Now when the server receives a request, it checks the database to see if a user has this token.
If it does, it checks the time in which the last request was made.(This is to handle cases when user login is timed out.). If the difference between the current time and the last request time is more than the limit you set, you responsd to the application that a fresh login request is required to generate a new token. Otherwise you continue with the request and respond with the results.
This is how the server side guys in my workplace does it. Im work on the client side. But this is basically what is done.
Edit: About the token.
Its basically a 32 character string which is generated with a random generator method. So when a user sends a login request and the login is success, we create a token using the generator method and store that into our server database as the users request token along with the current time and date.
So when the user sends another request to ther server, we first take the token and check if a user exists with that token. If there is, then the next check is to see if this is some old request token. So we check the current time with the time saved in the database. If the request was sent before the limit (Eg 5 mins) then we update the last request time in the database with the current time and return the result to the client.
With this method you are kind of doing an authentication for each request by checking the token and the last request time.
Suppose you want your app to be logged in all the time until the user explicity logs off. In that case you do not need to check for each request time. All you need to do is save the request token on the client device. And when the user signs out, delete the token from the client. So he will be required to login the next time as he has no token. Its a bit more secure to save a request token on the client device than saving a username and password in this scenario.
There are many functions out there for generating random tokens.
I am working on builing an API and application section on a social network so it will be something like myspace, facebook, hi5, friendster, netlog, and many other's have application section, they all use a REST server method and most of them will issue a api key and secret to each application developed. The person who builds the app will pass the api key and a user signature that is created with a hashing algorithm based on the user's ID who is using the app and the apps' API key. The applications code should set a cookie with some information like user id and signature and time. So on my server end the REST part should I just build the signature the same way the app does, check to make sure they are the same, if they are I send the correct data back. My concern is, how do I make sure a developer does not set a user's cookie to keep them authenticated for a long time, should I compare the time the users signature was created and if it is like a day old then I will send a bad response back from the REST?
When a user first add's an application from my main site, I will load the application site into an iframe and I will pass in user ID and other fields where I include the iframe so the application can use GET to initially get the information it needs to set it's cookie.
If you can help on this issue I would appreciate it, does it sound like I am in the right direction so far?
BTW I am using PHp/MySQL
I would store the token & user identifier that you pass back via the API in a database with a timestamp. When the user checks in via API to authenticate, check that timestamp and see if it is too old. If it is then pass back something like FALSE which would trigger some other command to make them re-authenticate into your system, which in turn would generate a new api token for the user to use.
Store a time() value in a session and every time the user does something check that time value to see if it's been longer than X minutes.