I've read many, if not all, answers to previously asked questions about the same topic, but questions themselves are not exactly about my case.
I have an OAuth 2.0 server running. It has an endpoint that provides access tokens to users. Programs and websites requesting the access token may or may not be owned by me, in other words, I may add a tool for website users and locate it on the same or neighboring website and my users may create an app and with their API key request access to user's data. Now I am developing the app that will operate user's data.
I realize that storing the API secret on the device is not a good solution. I have read about creating an end-point to which I make request directly from the app and then the endpoint makes API requests, but the endpoint will have to exist on the same host and probably server as OAuth server.
Is there a way to authorize mobile application to access user data when I am in controll of the application and the OAuth server? Should I create a separate end-point? Should I pass it device ID and/or any other information?
P.S. I know that plain old authorization would work here, but then what if some user wants to create his own mobile extension (not allowed currently for security reasons)? Also, current system has a button that is recognized by many people and they know what exactly will happen after clicking it. With the app, it may be an issue when the user sees a login dialog instead of the "Login with *" button. I really hope there is a clever solution to this.
Your concern is spot on. Your API Secret should not be stored on the device.
However, I am not sure why you would be concerned to build a separate endpoint, since OAuth 2 has a authorization flow for these use cases.
https://www.rfc-editor.org/rfc/rfc6749#section-9
In your use case, I'd suggest using the implicit grant flow to fetch the access token and store that on the local device. There would be no refresh tokens and the access_token can have an expiration date. Of course, the token on the device can be compromised, but the damage will be limited to a particular user and not the entire application.
If this level of security is not acceptable, then you can look at splitting up your API Secret in different parts of your app and then assemble it at run time in your app.
Related
How can you uniquely identify a user who has installed your app so that:
You will know it is them if they delete and reinstall your app;
You will know it is them if they install your app on a second device they intend to use simultaneously?
Just as an example, I see that the Netflix app will automatically link to your desktop account without any user interaction. I'm guessing that they use accountManager.getAccounts() or similar method, because they also require the GET_ACCOUNTS permission. But of course that permission is marked as Protection level: dangerous. Is there any technique to do this that is less invasive or potentially alarming?
The key to answering this is to be both simple (for the user) and minimally invasive. Android provides heaps of ways to identify users and many of those ways involve piercing a user's privacy, and if that is the only way, I will do what I do now (optional email registration). I just want a way for my app to know if a user already is registered in my system across installs without having to interview the user (username/password, email address, third-party OAuth, etc).
My main reasons are:
I don't want support requests from users who orphaned their content after a reinstall; and
I don't want to host lots of orphaned content.
Have a look at Firebase Authentication. It's quite seamless and does not require much effort to incorporate. Also it does not feel intrusive or cumbersome to the end user.
Here is a video tutorial by Google.
EDIT:
In case your users are sure to have a cellular device with a phone number, you can use AccountKit. It is also what they call OTA (One Time Authentication). AccountKit uses just the users phone number to verify and validate users.
EDIT:
Firebase Authentication now features 'Phone Verification' which is similar to AccountKit mentioned above. Both are good services. However, Firebase phone verification lets you make your own UI from scratch (which means a lot better control than AccountKit). Also, if you don't want to make your UI, you can always use FirebaseUI
i have implemented something that seems little similar to your thing by push notification , i can get error if user uninstalled my app(and from the registration id i get the user) , and if he re installed he obtain a new registration id , and try to get the user UUID for different devices
I think the simplest way would be using UUID and storing the hash on sharedPreferences. You should generate the UUID as earlier as possible in your app.
sharedPrefs = context.getSharedPreferences(APP_SHARED_PREFS,Activity.MODE_PRIVATE);
if (sharedPrefs.getString("YOUR-KEY-TO-THE-UUID") == null || "".equals(sharedPrefs.getString("YOUR-KEY-TO-THE-UUID"))){
prefsEditor = sharedPrefs.edit();
prefsEditor.putString("YOUR-KEY-TO-THE-UUID", UUID.randomUUID().toString());
prefsEditor.commit();
}
I think that the best way would be implementing login with Google or Facebook. This is quite seamless for users, safe enough (as Google and Facebook considered trusted), you do not need to implement your email registration and you will have identity across devices.
If your app is Android only and you'd like to provide identity without any account creation for the user, I believe using Google Account name/id is the best choice (Accessing Google Account Id /username via Android) since you have to use Google Account on Android phone (unless you root it, delete Google Play Services etc).
If you'd like to only address the first point of your question (identify after reinstall) there's a Device Id -Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
though it's not 100% reliable (f.e Factory Reset resets this value)
The standard for achieving this sort of functionality is through the use of JSON web tokens (JWT) in conjunction with standard restful api traffic.
Assuming your android application interacts with a RESTful api for all crudlike operations and business logic, then using a JWT as an authentication identifier to your api can work quite well. You can embed information in each JWT allowing you to identify whatever you like (the user id in the database, the device id of whereve the user logged in from, etc). A JWT is essentially a datastructure allowing you to store information to be used by the API.
Some basics for how this works:
Getting the JWT into the app: A user logs in to the application using their username/password. The
api then returns an encrypted JWT to be used by the client for all future requests. Don't try to do
the encryption yourself. Any language that can handle serving an api
will have libraries for this.
Using information in the JWT: The JWT is itself a datastructure. For example, it might look like this:
{
user_id: 1,
device_id: 44215,
device_os: android,
}
Your api will decrypt the JWT when it is supplied for
authentication via the request header, and then have that information available in the
context of the session.
If you provide the language used by your api then I might be able to recommend a library.
I will conclude by referring to the final requirement you submitted which states essentially that you do not want to have to interview the user across installs. If I understand your meaning, that you want a user to be able to simply install the application and begin using it without supplying authentication credentials, then there is no way to achieve that securely. You might be able to come up with a hackish way to get it to work, but it will be fundamentally insecure.
My web server has a REST API. I need to add user authentication to my app, and my thought process behind it is this:
Get the user's username and password from the app form
Encrypt the password and Base64 encode both the username and password
Send the data to the REST API over HTTPS
Web server verifies credentials, returns errors or success
Is this secure? I see a lot of mentions of OAuth2. What is it? What does it do better than my process?
The fact that you used the word "encrypt" for the users password instead of "hash" demonstrates you have fairly limited knowledge about this. This will almost certainly result in you messing up your authentication procedures somewhere along the line and put your users private information at risk.
A really important point about OAuth2 is that it can be used with many existing third party providers (Google, Facebook, Twitter, etc) with minimal effort from you.
You don't need to do anything to store credentials or even authenticate users. The third party takes cares of all of this and simply provides the client with a token (long random string) which is then passed to your server. Your server then talks to the third-party server to make sure the token is valid (and gain any info you need, like the users' name, email address or other information).
You really should consider using it if you can. The big companies put a lot of effort into securing their authentication methods and you gain all of that by making use of it.
A final nice point is that users don't need to create and remember credentials for (yet) another account.
Google has some docs to get you started and includes an OAuth playground to test how it works in practise.
A very basic explanation of OAuth2 is that the user will log into your system, with it encrypting both username and password before sending it, then if it gets authenticated, it will send back a token to the user.
Thereafter, whenever the user tries to contact the web server, it will send this token along with each API call. This is how it makes sure that non-authenticated people can't access your web server.
So basically your current method includes parts of the OAuth2 standard, but not the most important part (The token).
In your situation, how would you stop non-authenticated people from accessing your web server? If the project is small, then the risk of this is not that large.. But for larger companies, this is a real threat that needs to be dealt with.
You should really try to understand the difference between encryption and hashing before providing an authentication portal for your users. There are many different hashing algorithms you can use. I've personally used BCrypt in the past and I have a related SO Question about it as well. You can find implementations of pretty much all the popular algorithms in pretty much all the major high level languages these days.
Obviously if you don't want to do all that you can use an OAuth provider, who will take care of all the hard bits like storing the passwords securely, protecting the database and all the other security aspects for you. There are many reliable OAuth providers, Google, Facebook, Yahoo, etc. etc.
One thing to bear in mind would be the environment in which your app is hosted. OAuth does depend on having a connection available to the OAuth provider's servers every time a user wants to access your app. So, if you are behind a corporate firewall or similar which may block access to websites like Facebook, this might be a big problem.
I personally prefer token based authentication for my API projects. If you're not familiar with token based authentication you can read this SO Question and this link.
The general concept behind a
token-based authentication system is
simple. Allow users to enter their
username and password in order to
obtain a token which allows them to
fetch a specific resource - without
using their username and password.
Once their token has been obtained,
the user can offer the token - which
offers access to a specific resource
for a time period - to the remote
site.
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.
Let's say I have this application developed for Android which needs to use a Facebook (or Twitter or Google or all of them) based authentication so it can access this private API I've developed with nodejs' Express for example (could be any other platform too). I've read this answer here that gave me a hint on how to associate my authentication model with my user model (and another one here that made me realize those two parts are different), Facebook authenticates and I use some information they provide to create an "identity" for this user, but what exactly is this information that will create a link between the user and the identity? no abstract terms please, do I need to use and send either the access token or the Facebook user id? or would I just send the access token and let the server get the user id?
Regarding new requests after this user has been authenticated, I've read about API keys of some sort, which are basically some random strings that I should add to my identities (or users? this part confuses me) entities, and they should be securely stored in the mobile device as a mechanism to authenticate further requests, but how do I securely get this random string to the device in the first place? am I misunderstanding the way API keys work? are Facebook authentication and API keys mutually exclusive? if so, what would I use for further requests just using a provider for my authentication? it seems illogical to pass the access code in every request, even more so passing the user id.
The focus of this question is for me model a solid strategy for managing this authentication-user-identity behavior, would love any insights on how has this been done before since the material I've found in SO and the web has been very lacking, often referring just to server side implementations or just authentication answers, not addressing the issue of further requests.
The Facebook/User ID is there to identify the (returning) User. Keep in mind that you only get an "App Scoped ID", not the "real" ID - it will be unique in the App, but different in another one. See changelog: https://developers.facebook.com/docs/apps/changelog
Access Tokens are there to make calls to the Graph API. There are 3 different Tokens (App Token, User Token, Page Token), you can read more about them in those articles:
https://developers.facebook.com/docs/facebook-login/access-tokens/
http://www.devils-heaven.com/facebook-access-tokens/
You can store Access Tokens for later, but in most cases you don´t need to store them - only if you need to access the API while the User is not using your App.
In general, App Tokens can be used to request public stuff and to change App settings. User Tokens can be used to request (or post) User stuff and Page Tokens can be used to request insights of a Facebook Page and other things.
If you want to deal with Access Tokens on your own, make sure to activate appsecret_proof in the settings. I suggest reading this article about securing API calls: https://developers.facebook.com/docs/graph-api/securing-requests
We're developing a JSON REST API in Rails to be consumed by an Android application, which we are also developing. Is there any way to secure the API such that it can only be used by our specific Android application?
The API is read-only, and does not involve any kind of user-related or otherwise sensitive information. But to the extent that is reasonable we'd like to prevent abuse and restrict its use to only our app.
I could easily add an authentication token to the API and distribute it with the app, but:
We'd probably have to move the API over to SSL, if we use BASIC auth.
It's probably trivial for a determined person to open up the Android APK binary and uncover the auth token anyway.
The situation seems analogous to a café posting their WiFi password on the shop counter- you have to give the secret out to everyone who wants to use your service, so it almost seems pointless to have it in the first place.
What's the most reasonable approach to take?
Wanting to secure a probably public undocumented API so it can only be accessed by one application, means you want to stop people from using your API who are determinate of using your API.
Meaning people who would try everything possible to use your API.
If this is not the case adding a Auth token won't be trivial but at least a big stepping stone for people who stumble upon your API. And not a very bad idea to implement this.
Because this authentication isn't user based but application based and you don't want authentication to rely on user input. The request must be purely done so by the application.
Meaning you will have to do so anyway(adding hardcoded token). Only you make it very very difficult for a determined person to uncover the access and request tokens and the methods.
It depends on the situation, but I would go for the SSL and hardcoded token.
Some extra security:
Release an access token to the application which only need to send a
request token periodically. Meaning less chance people intercept the
hardcoded request token, but a session based access token which
expires. Maybe just do this once for every application install.
Encode this request token before sending it through the air. Meaning
people have to decompile your app.
Obfuscate code (make it more difficult to decompile).