I am new to PHP :). I am creating a REST API with PHP which would be used by mobile clients(Android and IOS). Currently the PHP website(yii) allows users to login with username and password(hashed and stored in DB). The way I think of implementing this is, I can have a login REST api call that authenticates the user and generates a token(some random number or sessionid) and sends a hash of that token to the client. The client then can pass that token on the http header everytime on the REST api call and the api methods will validate this on every call?
Now,
I want to know if there are any disadvantages of this approach?
Also are there any PHP examples of how to do this?
How does this token ensure security? Can someone sniff this token and send it in the request and the server will still allow it? Or Assuming i expire the token with time, should the mobile again authenticate to get a new token?
My answer isn't going to be the only one and I am sure you will get a lot of feedback on such a question.
First the hash. I wouldn't suggest doing it this way. The hash can be snitched in route by man in the middle attack etc. Generally sensitive information in the URL is a bad idea.
Why not use a common session? Authorize on the first call... then the session have been created on the server and the caller... this way you ensure that requests coming next is authorized.
The user/service/server can simply refer to the session cookie created and by doing so be validated. This way is much more secure and doesn't expose sensitive information.
And.. use HTTPS if possible of course... otherwise the information is also acceptable to attacks. It all depends on what level you want security. You can stack layers of security... but that might not make sense if your sending information about cats over the line :)
Related
I would really like some opinions on whether the following is a safe method as user authentication, and if not, please point out it's shortcomings.
React front end
PHP / MySQL based RESTful API on remote server
1) user signs up, data is posted to the API, user is emailed a single use activation link to ensure email is valid before they can access their account.
2) user signs in, API validates the data in all of the usual ways and then sends back a JSON object containing their user ID and an access token.
3) user ID and access token are set in localStorage on the users device upon receiving the data. React then grabs that data from localStorage and uses it to set and control the state in Redux stores providing an App wide Auth state.
4) user ID and access token are sent along with every future request made to the API. In the instances where a user isn't logged in, i.e - they don't supply a valid user id with matching token, they are automatically prevented from requesting anything that requires authentication at the very first entry point of the API. Suitable responses are sent back which in turn update the front end state to reflect a non-logged in user.
5) When the user logs out the access Token is deleted from localStorage.
A bit more detail about some the inner workings :
All tokens are generated server side and stored in the DB, they are random and unique bin2hex(random_bytes(32)) and only valid when supplied with the matching user ID. So changing the user ID in a request will result in a failed auth response, as will supplying a valid user ID with a mismatching or expired token.
Tokens are single use and a new token is generated, stored and then sent back in the response from every authenticated request along with the corresponding user ID. This may be overkill and put a lot of extra strain on the server. Would really like your opinions on this aspect especially please.
Tokens are set to expire in 2hrs regardless. So if the user leaves themselves logged in, they will be automatically logged out after 2hrs of inactivity.
User ID and Token are sent as part of the JSON body of every request (not in the headers). Is this a cause for concern?
At no point (other than sign up and login) is the users password transmitted or stored in localStorage or used by the React frontend. A matching user ID and Token is all that is required to validate the user after the initial authorization.
All connections are made via HTTPS.
Can you spot any glaring security risks in this approach? Am I missing the elephant in the room here?
Obviously the user ID and matching token is as good as supplying the users email and password on every request as far as auth goes, but I can't use PHP sessions or cookies* as the API is hosted on a different domain. This is the best workaround I could come up with without having to go down the JWT or Oauth route.
How flawed it could be in regards to how I am checking and validating data on the API can't be practically addressed here, but assuming that it is all being done correctly is this method secure enough in principle?
I look forward to and thank you in advance for your opinions :)
*without a ton of workarounds which would ultimately be superflous as this App can only be used with modern browsers which all support localStorage.
In my opinion is not save to store the token in the local store,
As said in https://auth0.com/docs/security/store-tokens
Since Browser local storage (or session storage) is not secure. Any data stored there may be vulnerable to cross-site scripting. If an attacker steals a token, they can gain access to and make requests to your API. Treat tokens like credit card numbers or passwords: don’t store them in local storage.
A better option is to use cookies since they are managed by the browser.
This is more of a procedure question question than a code fault one so please be kind if I have posted in the wrong place.
I have successfully authenticated a gplus user client-side so the browser is holding the google id ready for me to use. I now want to post some data to my website with that id as the user id but i want to protect it meaning I don't want just anyone with someone else's gplus id to be able to post to my web app (it has to be the authenticated user at that time).
Should I install the php serverside sdk and use that? If so how do i merge the client-side data with that?
Thanks
You're absolutely right about wanting to get the ID in a secure manner to make it hard to impersonate. There are two main options, both properties of the authResult object that comes back to the sign in callback:
Send the 'code' to the server. This is part of the OAuth 2.0 flow, and can be exchanged on the server side for an access token. From that you can make API calls as the user, and retrieve the user ID and other details. You can be confident who the user is, as only Google could have generated that code. This would involve using one of the client libraries to handle the token exchange.
Use the id_token. This is a base64 encoded blob of JSON which includes the user ID (and email address if you requested the 'email' scope). What makes it secure is that it includes a cryptographic signature, which the server can verify, so it cannot be created by someone other than Google. The id token can be used to get the user ID, and so can be used for looking up the user on the server, but doesn't give access to make API calls. The benefit is that it only requires up to date certificates for verification which don't change that often, so most calls require no further network traffic from the server to verify the user.
Which you use is up to you, but both will require some code on the server. In general, if you don't need to call any Google APIs from the server, or are concerned about maximum login performance then use the id_token. There's a bit more about that sort of architecture here: http://www.riskcompletefailure.com/2013/11/client-server-authentication-with-id.html
You can even combine the two. The first time a user signs in (when they see the consent screen) the code exchange will return not just an access token (for making calls), but also a long-lived refresh token, which you can store securely in a database. If you store that, you can use the id_token to look up the user quickly, but still use the refresh token to help with API access.
Note: I know there are LOTS of other StackOverflow questions dealing with this topic. I've read through many of them, as well as many other websites. I still have the following questions.
So, I'm building a REST API for a new product. At this time the API is entirely for private consumption by our websites and phone apps. However, I'm thinking it might be smart to design the API so that it can be made public in the future.
Authentication
While I've looked at OAuth, I think HTTP Basic Authentication over SSL is plenty secure enough for our API. From what I understand HTTP Basic Authentication over SSL is a completely viable way of authenticating a REST API. It's also quite simple, which is appealing for me since I'm new to API development.
Authorization
If a user logs in to the API using their username and password, they will only be given access to certain parts of the API. Meaning they'll have access to their own content, but not the content of other users. Further, they may be limited to what they can all do.
In addition to the user accounts, I plan to also have other other (non user) accounts for more global administrative tasks. These accounts could potentially have full access to the API.
Is this a good design? OR, is it bad to authenticate a user in this way? Should I only be authenticating my clients (ie. apps) this way?
Sessions
My big question is, when logging a user into our web app, how do I manage their sessions? REST stipulates sending the username and password with each request. Further, REST API's are stateless, so I cannot manage sessions there. However, I need to track that they've logged into the web app somehow. They clearly can't possibly login manually for each request.
One approach is, after a user logs in, we save their login credentials (email & password) to the PHP session. Then, each subsequent request to the API could use those credentials. However, saving usernames and passwords in a PHP session just feels wrong and very unsafe. But if not done this way, how are people managing sessions when interacting with a REST API?
The phone apps are easier, as you can save the user's login credentials into a keychain.
Can anyone help with my design questions?
I know this question is a bit old and maybe you already finished your work, but I'd like to give you some tips. Maybe these could help you or anybody in the future. :)
Authentication
HTTP Basic Auth over SSL is quite simple, that's true, but not so secure than you think. You only have to install 1 "fake" SSL cert on the client and with a man in the middle attack you can sniff the traffic.
How to install a fake certificate? It's not so hard in a browser lot of users just click on the ok when they see the huge red warning screen. On a mobile for example: http://cryptopath.wordpress.com/2010/01/29/iphone-certificate-flaws/
With this solution you only have to intercept the traffic once and you'll have the user's password!
My tip: Generate a temporary password at login and use this in every other requests. So the attacker have to intercept the login process for the password and if you store this pass locally on the phone for example it's much harder. (And of course you can add expiration to it etc...)
Authorization
I don't really understand what would you do. User access management is a good thing, but it depends on the given project.
Session
Not only the REST APIs, teh whole HTTP world is stateless. If you use a PHP session it stores a session id in a cookie on the client side and the browser sends this cookie value every time to the server.
The users don't have to login every time. They log in once and get a token/temporary password etc... and (or if you don't use these stuff) they send you a basic auth header at every requests.
This way you can easily track who sent you the request, because you already now who's that user and you can store and link some data to it on the server.
There are many ways to deal with users. Basic auth is one of them. And check this: OAuth's tokens and sessions in REST
"OAuth tokens are explicitly a session identifier, ..."
You don't have to store the user's password and email, you just have to check the headers/cookies/etc... from the client in every requests.
The phone apps are easier, as you can save the user's login
credentials into a keychain.
They can, but saving the user's real password on a phone is a very bad practice. Save a time limited token is a bit better. :)
In every other languages you can store values if you want. For example if you want to use a Python client for your API: It authenticates and stores a token or something what it needs in a variable and at every other requests it uses this stored data.
One more sidenote:
However, saving usernames and passwords in a PHP session just feels
wrong and very unsafe.
True that's unsafe, but the (real) PHP sessions are stored on the server side and as I said it stores only a single session id on the client side. Anybody who can get this session id, could impersonate the given user. (There are countermeasures for example IP check, etc...)
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 am developing a mobile application using PhoneGap which will communicate with a server(PHP) via ajax requests.
On the server side(PHP)
Something like https://example.com/retrieveData.php
will get the user id via $_POST['user_id'] and return some sensitive information about the user as JSON.
And on the client side(PhoneGap-Javascript)
that JSON output will be parsed and will be used in the application.
My concern is that if someone steals this url ( https://example.com/retrieveData.php ), he can manually send fake post requests and can steal the returned user information?
How can I secure this communication?
My concern is that if someone steals this url ( https://example.com/retrieveData.php ), he can manually send fake post requests and can steal the returned user information?
You are right to be concerned. Anybody can send a message to that URL, and get the result unless you check some part of the request that authorizes the request.
For example, you could authenticate to check that the request comes from the user and then authorize the request based on the idea that the user should have access to that info.
Alternatively, you can authorize based on something that only a valid requestor would know via a shared secret and rely on the https part of that URL to prevent shared secrets from becoming public. You give out the secret to trusted partners, and when you generate a web form via PHP (also protected via HTTPS), you include a hidden input containing the shared secret. This is how XSRF protection typically works.
You should think about the following:
Who should legitimately be able to reach this page? Logged-in users interacting via your phone app, partners who can protect a secret, web API users?
What credentials do they have for using other parts of your server? Log-in cookies? XSRF tokens? Partner tokens?
What parts of your app are sent only over secure channels like https?
If all of (1) is satisfied by some subset of credentials in (2) and those credentials are only ever sent over (3) then you just need to check (2) in your page. Otherwise, you need to rework your application architecture until that is true.
OWASP has a Guide to Authorization that might come in handy and they also have a number of pages on reviewing authorization code but most of the examples are not PHP specific.
Of course he can send any post request he wants. The only possible way to get around this is with authentication that the server knows about, i.e. the client has to send you something hard to guess and that starts a session in the server.
As other answers suggests, following is the strategy to make your webapp more secure :-
The most basic rule, use secured protocol(https)
Authenticate
your user through username and password
Most of the
features/operations of your app primarily must require user to be get
authenticated.
Apart from authentication, Maintain Access Control
List for your app, which decides authorities each user role
have(Assuming that you divides your users into different roles).
Prior to performing any operation on behalf of user, check if user is
authorized to do so.
Don't rely only on client-side validation.
Perform validation at server side also.
Send csrf_tokens along
with your response, along with session cookies.
Never send any
confidential information in cookies.
Hope it helps.