I am developing the PHP based REST api. I have android app which will send some key parameters to server and the server will respond with the data. In this case, the email is the key element to get all the relevant data. If I want to make it secure, I can save password in sharedPreferences and send it at every request. This might make communication secure, but I understand that sharedPreferences are not secure and putting confidential information in them is not recommended. Also, I cannot store a hash of password in sharedPreferences because I am using the password_hash() function in php api which requires password as plain text. So, i have to send request as a plain text password only. What should I do to make it secure?
There's the normal way things like this are done and that is usually with some form of token authentication.
However, you probably want to learn more about security except what you're doing is a toy app only you intend using. With that being said, PHP is very wonderful at handling sessions, so you can consider using a cookie jar in your app and take advantage of sessions. REST purists will probably hang me for that suggestion, but you know what? It works perfectly provided you're gonna be using your API for just your app.
Another quick and easy solution is to do a normal email and password login from your app. On success, return a randomly generated token to the user and also store in a table on your database. This token is what you can store in sharedpref that will be sent along with every request. To make things more interesting, you can allow the token expire after say 10 minutes if it hasn't been used. On your app this will mean the user needs to login again, and generate a new token.
If you're going with the token generation model, you wanna make sure the token is not easily guessable. I usually just use something like this for those kind of random alphanumeric strings:
$randomLongString = hash('sha384', microtime() . uniqid() . bin2hex(random_bytes(10)));
For the expiry, you can record the timestamp the token table was accessed, store it in a column with the same token. If the old timestamp + (expiry time) > timestamp now, then you know the token is expired. Return a 401. If not update the old timestamp with the current timestamp, then return a 200.
These are relatively simple but effective solutions that work for single server setups, and relies on the fact that the user is still the same user. Other things you could do is IP checking, device ID verification before you generate the token. And if any of those things change along the way, you quickly invalidate the token and provide a way for the user to prove they are who they claim they are.
OAuth2 with client_credentials GrantType is the best option in my opinion.
For tokens I would use JWT (which is default in most PHP implementations) which gives you the ability to validate it stateless and makes your auth env more scalable.
You would the authorize your app using a fixed set of client credentials (client_id and optional client_secret) to authorize the user with its username and password against the auth server. The received token is then stored in sharedPreferences for further authorization.
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.
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 :)
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.
I want to make a light webapp on top of a REST api, where the user should authenticate only once, from then on all request against the web api would hopefully be done by keeping alive the username and password in some way.
I have already made a working prototype where I store the username and password in session variables if the first request to the REST api is successfull, and from then on every request is made with auth info gotten from the session variables. So far so good.
With this approach, I realize someone with access to the server would be able to read the password. Is there some way in PHP that i could follow my approach with an appropriate amount of security?
Update with some further details:
The intended goal here is to make a visualisation of data retrieved from an API, based on querying it with different data, but not having the user enter his username and password for each attempt. So the API is totally stateless, but the web application with gui should be statefull.
In this case I have no control over the Rest API, so each request to it will always require sending the API username and password with basic auth, there are no alternative schemes such as a API key, session token or anything like that. This is why I have to retain the username and password for as long as a user session lasts, and I wanted to know if the approach with storing them in session variables could be considered secure.
As long as you're not storing session state on the REST API server, only on your client webapp, it seems fine from an architectural point of view.
If you really must use the username and password and can't get a disposable token, you may encrypt them with a server-side key, and decrypt on-the-fly when you send them to the API, so even if someone can hijack a session they can't obtain the username and password without the server-side key, but you should be a lot more careful with leaking your php session anyway.
PHP Session Security.
Follow the steps outlined in the answer for that question, except that you should use HTTPS for all interactions, between the user and the webapp, and between the webapp and the REST API.
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...)