I've noticed a lot of apps, even ones that handle sensitive information like finance apps, have this security model: the user first logs in with username/password and from then on just has to enter a PIN to access the app. I was wondering how this is usually implemented. Is it just done by storing hashed credentials into a local database and tying them to a PIN?
Username/password login should be the default for authentication and authorization on a remote server. You can set up your app to log in once, get an auth token from the server, and then use this auth token to log in for subsequent visits.
As an alternative, you can ask the user to log in every time.
You should use a PIN to restrict access to the entire app, including any local data. Having said that, PINs aren't particularly secure. If you want an additional level of security, consider using an OTP.
Related
I've been mostly creating smaller apps and games for Android so far, but am now creating a somewhat big app with lots of users and more sensible data than a highscore.
My normal approach was to just have a table for all users with passwords, authenticate with a simple Login Screen using a HTTP(S) call and that's it.
There's a few things I want to improve for this app though:
Secure Transmission
If I want to encrypt the user's password, where do I need to do it? On the device, before it's even sent? (In case of unsecure networks, like a public WiFi hotspot) Or better on the server, before writing it into the DB? Or should I just use SQL's encryption?
Auto Login
I want users to be able to stay logged in until the log out - how would I best do that? Not just security-wise, but also for the user experience.
My research shows me that using the AccountManager would be best to save the username and password and authenticate automatically when the app is started. Is there anything more to it, any security risks I'm missing here?
Access control
Usually, I would just expect every call made by an app to be valid, since a user can't access anything but the login screen without logging in. But how do I best authenticate a user's request to make sure that it's not an attacker? I can't just send the username/id with every request, so I probably need like a session token that I generate on each login? Or is there a better method?
Is there anything else I've forgot to think about?
I would suggest you to transfer password without encrypting it but by https. Other way would be to implement asymmetric encryption in your app and encrypt password with public key which you will receive from server.
On the server side I would hash password using some hashing algorithm with salt. And store only hash and salt. When users will log in, you can hash incoming passwords the same way and check hashes on equality.
To make auto login, you need to sign all requests from authorized users with a token. Token you will receive from the server after successful login. This token could be stored in Keystore, or special storage which is accessible only for this application.
Signing could be implemented by attaching to request additional parameter with checksum from all request parameters and token.
Additionally I would suggest you to think about unauthorized clone apps, which could pretend to be your app and call your server side API.
I've been doing a lot of search about secure my api for mobile apps for Android or IOS.
Almost all examples tell user provides an user id and password somehow in a exchange for a token.
But how to prevent someone else to consume my api without my consent?
Face the following scenario:
I expose an API,
I develop, then, an app for android to consume it,
I develop, then, an app for IOS to consume it.
Other developer performs a rev. engineer in my app, creates his own app and starts to consume it without authorization.
How to prevent that?
Short answer: you can't.
Little longer answer: If you know what you are doing you can always reverse engineer a given application and use its api. You can only make it more difficult and time consuming, using authentification via tokens and device ids or usernames is a good first step. Apart from that: why would you want to close your api to outsiders? If your server code is written well there is nothing to worry about.
You can maybe secure your API on a legal basis and sue developers who use it, but that is a completely different topic.
Some clarification regarding securing the API and securing content via the API. Assume you create a server where you can send user/password and receive a token if that combination was correct. For the account-page you send said token over and the server verifys that that token is valid and returns your account page. You secured the actual content of the API. That is obviously very possible and almost a must-have unless you have no user-specific data. But still everybody can send the exact same initial request from their custom app, sending a user/pass and again receive a token, etc. You cannot really prevent the request itself or even determine that it was not send by some service not authorized by you. You can send some hashes along the request to add some security by obfuscation, but since your app has to compute them, so can the reverse engineer.
Yes, login api are open but they return a token only on successful match in your database. You should focus more on security of your data than unknown hits at your api.
SignUp API can be used for creating a user, and login for returning token of that user. Only if malicious developer has credentials, then he can access tokens and auth APIs. There is also something about DDOS attacks so you can maybe write logic to temporarily block IPs where hits frequency is high.
You can also store device ID of signing user, which seems idle for your scenario. Entertain hits from that deviceID only. Similarly, user can add more devices with their credentials. I think even Google does that (generate alerts if user creds are signed in from new device and add the device to list if user confirms). Hope this helps.
I want to maintain user session once the user logs into his/her account so that they are logged in even after the application is closed and started again. Searching on Google and SO, people referred SharedPreferences. I understand that I have to store user details in SP(SharedPreferences), but what if the user updates his/her data? Plus, the HttpGet call I send to the link to get user data returns the valid data(JSON) only when the user is logged in. Is SP the only way to do this, or is there other and more efficient way to do this?
P.S. - I am working as a freelance for a startup, and they have API to their PHP website. I have to make an android app for their website. To log in the user to the website, I make a Http POST call to their API and the result I get is a JSON. If the JSON contains "success" value to the "result" key, then the user is logged in. But as soon as I use intent to go to the next activity(where I have to display the user data by making Http Get call to another API, which only works if the user is logged in), the session is lost. Since I work as a freelance, they don't really trust me giving cookies to user sessions. So, I was hoping there might me some other way?
You can always use cookies (with, say, an authentication token?), Android OS manages them for your app automatically - as long as the cookie is correctly set by the server (ex. expiration date) your app should work fine. But this is a little old school.
A more modern way is to use OAuth or integrate an already existing login system (Facebook, Google, etc.) to authenticate users.
Using Shared Preferences is a wrong tool for this job. It's a workaround for doing proper authentication. There are ways that are trustworthy and secure and take care of all kinds of edge cases, and while it takes a little bit of work to set up, it's a much better option, IMO.
You should try to integrate android AccountManger APIs because storing the credentials in shared preferences is not especially desirable from security point,especially if your app is going to run on rooted devices.
From the docs:
public class AccountManager extends Object java.lang.Object ↳
android.accounts.AccountManager Class Overview
This class provides access to a centralized registry of the user's
online accounts. The user enters credentials (username and password)
once per account, granting applications access to online resources
with "one-click" approval.
Different online services have different ways of handling accounts and
authentication, so the account manager uses pluggable authenticator
modules for different account types. Authenticators (which may be
written by third parties) handle the actual details of validating
account credentials and storing account information. For example,
Google, Facebook, and Microsoft Exchange each have their own
authenticator.
Many servers support some notion of an authentication token, which can
be used to authenticate a request to the server without sending the
user's actual password. (Auth tokens are normally created with a
separate request which does include the user's credentials.)
AccountManager can generate auth tokens for applications, so the
application doesn't need to handle passwords directly. Auth tokens are
normally reusable and cached by AccountManager, but must be refreshed
periodically. It's the responsibility of applications to invalidate
auth tokens when they stop working so the AccountManager knows it
needs to regenerate them.
\
I'm suppose to develop a new option for our Android app that allows new users to sign in with their Google account. We need to retrieve basic user info (First name, Last name, Date of birth, Email, Country etc.) and store them on server. It should happen only the first time user logs in to the app so the next time all the button is doing is simple authentication to access the member's area.
Currently, our app prompt for permission using oauth2 and AccountManager and can retrieve the user info through oauth2 api. I would like to do the same thing on our server instead.
So to sum it up here is the flow I'm thinking about:
User chooses to sign in with Google
If he hasn't authorized the app yet, request permission to access his info; retrieve and store them on the server and log in. If he has already authorize the app, simply log in.
We still need a local copy of user info on his android device though so he can view his own profile.
Note: The reason I'm thinking of doing the data import process on our server is to speed up the app and save some bandwidth. but I also feel that user might want to modify his data before they get saved to the server.
I'm really confused and the oauth2 documentation doesn't help much.
I don´t understand the problem. Sorry.
Just retrieve information about the customer from the OAuth api, send the information through HTTP/HTTPS post request to the server, save it there. Then save the same information in the SQLite database in phone and after first time when the app launches just check the user table in SQLite for if the customer exists.
Here is an awesome example: http://www.androidhive.info/2012/01/android-login-and-registration-with-php-mysql-and-sqlite/
In order to do this, you need to follow the documentation for Cross-Platform single sign-on and Cross-client Auth from Google. In essence, your flow should be:
Check to see if the user is authenticated (probably best as a POST to your remote system), if so, continue to your main activity. If not, show the sign on button.
Once the user clicks sign-on, connect the GoogleApiClient, retrieve the current person, save their information on the device (if needed).
Request an auth token for the user via GoogleAuthUtil.getToken.
Send the token to your web server (must be https). On your web server, retrieve the user's information from the token, and save it to the database.
Also, I suggest you use a persistent cookie store for your requests (I prefer loop4j's Android Async-HttpClient). This will allow you to save the session easily, so you do not have to authenticate too often.
I'm a relative newbie to web and mobile development and especially to security so obvious answers are still appreciated.
I want my android app to be able to log in to a simple web service with a username and password.
What's the best way to send this information securely and keep the user logged in for an entire session?
Do you control the web service? If not then you will need to use whatever authentication mechanism the web service provides.
If you're writing the web service yourself, you have a lot of options.
The simplest is to just send the user's username and password via SSL with every request as a HTTP Authorization: header. The downside here is that you need to keep the username and password stored on the device. That being said, because of the way Android's permission system works, there's very little risk of an attacker stealing credentials off of the device, provided the user hasn't enabled root access.
If you still want to avoid storing the password in plain text, you can send the username/password once (again, using SSL), have the server return an encrypted authorization token, then send that token in place of the user's username/password. See Google's ClientLogin for an example of this. An attacker could still steal the token if they have physical access to the device, but at least the attacker can't use that to gain access to any other sites that use the same password.
There's other options out there as well, like using challenge/response to prevent the server from ever seeing the user's password, using OAuth to provide a common authorization API, and so on. It all depends on what your particular requirements are.
A friend and I are looking to do this same thing, and I think that we've settled on storing a web service key unique to the user on the device, and using that for authentication rather than storing un/pw (this is the second method provided by Trevor above). You'll need to make sure to provide for a means for getting that key onto the device as well.
You can use a server based random key and local imie based key along with users unique token for making a logic .you can put an expiry time for every key