I recently developed an application which was the financial app and it had undergone security vulnerability testing.
One of the point identified in the testing was-
Account Takeover Through Insecure Direct Object Reference-
The comment provided was as below-
During security assessment, it is found that insecure authorization controls in the Android application allow an attacker to make requests on behalf of different users. It allows an attacker to take over any user's account.
The application completely lacks authorization controls which allow an attacker to make requests on behalf of any user.
The remedy provided was-
To prevent this, ensure user's access rights are restricted to the correct privilege level and not just by the pages available to the user in the interface of the application.
Does this mean a role-based system? My app does not need multiple user roles. There is the only single role "End User" who will be using the app.
Can someone provide insight?
You need to consider the following,
Use Authentication methods for the web APIs such as basic auth, OAuth 2.0, OAuth 1.0
Use session manager for the user, even if only one user.
Use Gradle to save the data such as URL, token, token secret etc.
Use minimal 3rd party libraries.
Use proguard
Hide all logs
Change Debug variable to Release variable before release or test.
Implement OAUTH session management with access token renewal.
Each system has at least two roles: admin (privileged user) and (unprivileged) user. However, in real systems there exist several roles like editor, Finance manager, HR manager, etc. So, you need to provide these users with different level of access to the resources.
Related
We are building a mobile application and its API server with architecture as in the picture below.
We have WSO2 as the API gateway in front of the Spring Boot API Server. We use WSO2 API Manager to restrict who can call the APIs. Only clients that have registered with our WSO2 and have the correct consumer key and secret can call an API through WSO2, by which the client first call to WSO2's token endpoint to exchange the consumer key and secret with an access token, then call the desired API with the access token in header Authorization: Bearer <access token>
We have a problem that we don't know how to keep the consumer secret since security audits prohibit us to store the secret in mobile app installer package.
There were some questions already asked such as
WSO2 API Manager - How does mobile app connect to API Manager?
WSO2 Api Manager OAuth2 DCR security in public native mobile app
But no answers correctly point to the problem. Most of them was mislead by the complexity of oauth2 flow.
To make the problem specific and clear, please assume that our mobile don't have users to login. The goal of this problem is to allow only trusted mobile application to call the API through WSO2.
Please help suggest if this is possible or not. Or we have no choice but to allow anyone to call the API. Or WSO2' consumer subscribtion feature is not designed to be used directly from mobile app at all?
After doing some research, I found 2 options people usually do.
Separate APIs into 2 groups. First group contains APIs that need to be used without user login, such as API to get initialization data or to get data for landing page of the app. Thease APIs are set as public, allow anyone to call without clientId and secret. The seconds group contains secured APIs that required the token. Mobile app can use Oauth2 PKCE flow to exchange the token with user identity proof.
Obfuscate clientId and secret and keep them in mobile app installer package. The APIs are still be separated into 2 groups as before. But the first group requires client-level token (oauth2 client credential type) and the second group requires user-level token (resource owner password or authorization code type)
I prefer option 2. In my opinion, I think the first option does not really make sense. People choosing this option, maybe, just do it to bypass the security audit check list, to not store the secret in public client, without really concern about security problem. It's like when you cannot trust your kids to keep a key to your house safely, so you decided to remove the lock from the door.
Having every APIs protected and keep the key in the client. Even though some hacker can manage to find the secret, he can only hack APIs of the first group and you can track the clientId he used. You know the expect behavior of the client so it is easy to setup an alarm that detect malicious activities from the client and revoke the token, reset the secret and rollout more complex obfuscation algorithm.
You may want to read OAuth 2.0 for Native Apps [RFC7636] spec. It states:
Public native app clients MUST implement the Proof Key for Code
Exchange (PKCE [RFC7636]) extension to OAuth, and authorization
servers MUST support PKCE for such clients, for the reasons detailed
in Section 8.1.
Check the below answer too.
How to implement Oauth2 without sending client_secret in WSO2 APIM
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.
Background
We have developed a web application featuring a rest-api using oauth2/oidc and support for third party apps
We have developed our own native apps for android and ios. Currently they retrieve a long lived token from user credential flow (no consent screen needed).
We are currently extending our authentication flow to also accept external login by google/office365. This is also supported by specifying acr value in authorization code/implicit oauth flow.
Issue/Problem
We of course want to be able to fully trust our native app and not show a consent screen for the best user experience. While using the authorization code/implicit flow though nothing can be considered a secret and a malicious hacker could potentially exploit (without user knowledge) the user if no consent screen is shown.
How can we avoid having to show consent screen for our own native app while still being sure user is as safe as possible?
How to solve?
Doing a separate office365/google login to retrieve refresh token from this idp and then implementing a way to publicly authenticate using this token to retrieve a longlived token from our webapp.
Simply ignore security flaw and never ask for user consent given the nonsecret mix of `clientId/clientSecret/redirectUrl` with the excuse "it's quite difficult to hack this".
Ignoring security flaw if external login with the excuse "google/office365 should show a consent screen anyhow when requesting a refresh token".
Some unknown way to make sure that its not a malicious app/user
The reason i don't like (1) above is it both opens up a somewhat new authentication flow in our webapp and forces native app to implement a more complex authentication flow.
Is there something im missing here, what would be considered best practise?
The point is that Google needs to authenticate the user outside of your app to make sure your app does not see the user credentials and thus defeat the purpose of OAuth.
The user also needs to allow the app explicitly to avoid random apps obtaining tokens from the user: anyone with a Google account can create a client_id/client_secret/redirect_uri combo. You/your app is not trusted by Google with tokens for arbitrary users without asking those users first. As you mention at (1) the user only needs to go through this once. The app may retrieve a long-lived refresh token and keep using that to refresh access tokens.
Hence best practice is to spawn a browser/webview and handle the authentication/consent flow in there. There's no way around that. If there was a way it would be a vulnerability because the system was designed to avoid it.
I'd say something like nr 2:
Have a way to mark a client (identified by clientId and clientSecret) as trusted (e.g. with a superuser interface), and thereby automatically give consent.
The client secret should be safe; if it's not, you have other security problems.
I want to offer some functions of my webapp to be used in other apps (I'm thinking mainly about smartphones, since they offer more capabilities e.g. GPS, Camera,..).
From what I have encountered myself so far in terms of other APIs e.g. GoogleMaps, is that a 3rd party developer would register himself at my site, he gets an API key (some random UUID) and he has to use it to authenticate his requests against my website. So far so good...
Is there a mechanism to protect the end user of a mobile app from malicious apps? E.g. a 3rd party developer could build an app and capture all username/passwords from the end user, so that he can do bad stuff with the useraccount.
(E.g. I could build a twitter app, capture all the usernames/passwords and then delete all their tweets, post new ones,..)
Is there a possibility to prevent this? AFAIK you could use oauth on the web so that my website login box would appear on another site and ask them for their username/password, so that it isn't shown to the 3rd party site.
Is it possible to implement a secure authentication for smartphone apps? How would you do it?
For Android and iPhone you can use OAuth without problems, and so far I think this is the best way to be done.
The flow for these two smartphone types is the same like in web applications, because both OS give you the possibility to start web browser from your application and redirect the user to web provider, so he can authorize your request (token), and then the browser can return your user to the application via proper callback URI. I haven't implemented oauth for mobile phones, but I've heard from a friend that it's possible and that the mobile browser can redirect the user back to your app with some special URI, like scheme://app/parameters.
Here is something for this with android: link
There are two oauth use cases: 2-legged and 3-legged
2-legged is when you want to protect your API, so that it can be called only from authenticated consumer applications. This is a popular scheme that exists from ages AFAIK - the consumer signs every request with a consumer shared key, and the provider (your API), signs the request also to see if the signature match. This way you can tell if API usage is ok for that consumer.
3-legged oauth includes the end-user of the consumer 3rd party app. It is very suitable, if you want to protect your API again like in 2-legged, because requests are still signed, but also your API can be protected by the end-user's permission. The provider of the API issues a token and gives it to the consumer application (3rd party app). Then this app saves the token locally and redirects the user to Provider for authorization of the token. When the user authorizes it, the provider sends back the user to the consumer application and then consumer can make authenticated (signed) and authorized (by the user - 3rd leg) requests to your API.
The protocol is not very complicated once you read how it works, and is very flexible - you can extend it to your needs however you like. I would highly recommend it for protecting APIs, especially if user permission is required for access to the APIs.
This is a very good site to read about oauth: http://hueniverse.com/oauth/
--- ADD ON ---
There is some security implications regarding shared key storage in the consumer application - mobile phone app in your case.
If somebody open your program and disassemble the code and extract the shared key, then he can make application which will authenticate successfully to the provider API. However this is not a very big concern if user authorization is required (3-legged), because the user will still be asked to give permission to this false application - and now it's up to the user to make the proper choice. And besides that - the false app will not be able to steal user's credentials, because with oauth, user credentials are entered only at the provider's site.
On your second question:
The benefits of oauth are:
User can be asked for permission when sensitive API is access by 3rd party;
User will never enter his credentials at 3rd party app. Every 3rd party app is untrusted and is potential attack vector.
For example, if you are gmail - provider of API and you provide web service method login(user, pass) to 3rd party app developers, then they can make login screen in their app and log in the users. However in this process their 3rd party app directly receives user credentials before sending them to gmail. I would never use such application. The problem is that most people are not familiar (especially non technical people) with the consequences of such application usage and people making applications are still exploiting this old and insecure way of doing things. However, as more people engage to implement some security protocol like oauth (or similar), the people will become familiar with this flows and will become more suspicious to such intrusive 3rd party applications.
I say intrusive, because imagine for a moment the following scenario:
You can make a payment API in a not so developed country like Bulgaria or Albania. This is a very good opportunity for businesses to use, because Credit Cards are not a common payment method at all at these locations.
And this provider API is protected by exposed web service method login(user, pass). After 3rd party app use this method with user credentials (which it has already taken), it gains access to charge(user, amount) method. It can then call this API method with whatever parameters it wants and charge the user with one hundred thousand million pessos :D
The user will not even know until later. And besides, you cannot separate API method calling by permissions - what the user is agreed to and what not.
Other drawback is that users use one password for many places - this way 3rd party app can gain access to another service that the user may use with the same password.
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.