REST API Authorization type - java

I have read a lot of about the way to provide acces to a REST API and I still cannot come with a decision what to use.
In my case I am writing a REST API that will be used by the users of the mobile application(android&iOS), thus I do not provide or require access from third parties and this makes me think that I don't have to use OAuth.
However I have considerations about how to provide access of one user's account from multiple devices and how to provide offline access.
Another consideration I have is how should I restrict the API access, for example if using API Tokens what are the best practices for expiration and renewal of the tokens?

You have several topics in your question:
What are the benefits of OAuth2 for an internal API exposed on the Internet?
How should I manage tokens?
How can a user gain access via multiple devices?
How can a user have offline access?
I discuss these questions below.
Oauth2
OAuth2 offers a standardized protocol for several authentication schemes of varying complexity. One of the most complex use cases is the 'Authorization Code Grant' flow which allows a resource owner (user) to grant specific access to a client application via an intermediary, the Authorization server. This is what happens when you 'login using google'. The advantage of using OAuth2 over a homebrew solution is that the protocol is clear to all parties and less likely to contain fundamental flaws. A drawback can be that the protocol is not that flexible so some custom scenario's might be hard to support within the boundaries of OAuth2. If you don't have the immediate need for any of the typical OAuth2 scenario's (or a stakeholder demanding use of OAuth2) then I suggest not starting off with it, but to implement a simple token scheme yourself.
Managing tokens
The most common way to manage API access is by using tokens. A token is generated when the user logs in, typically with username and password over HTTPS. The token is persisted on the server and must be supplied by the app in each request. This is similar to the session ID used in web applications which is automatically generated and handled in-memory by the application container on the server and passed via a cookie or request parameter. An API token is typically handled by the security layer of the application itself, persisted in the database and passed via the 'Authorization' header.
A token should have an expiration date. One should decide on the best interval for this and whether token renewal is automatic (each time the user accesses the API) or explicit (force the user to re-enter credentials after expiration). This depends on the type of application and the level of security required. Tokens can also be revoked manually on the server.
Multiple devices
Each token can be associated with a specific user and device to allow access on multiple devices. This means each device must be uniquely identified, typically with the IMEI code. This makes it easy to revoke all tokens for a specific device or user at once.
Offline access
The typical way to offer offline access is to cache relevant data on the device. For example the Google Maps app allows you to make specific regions of the map available offline. To avoid (too) stale data you could keep track of the token's expiration date and invalidate the cached data after this date. An issue to be aware of is the handling of offline edits by the user. These edits have to be processed when the device comes online again. When simultaneous edits on the same data are encountered a strategy is needed to resolve the conflict, e.g.:
one edit overrides the other depending on the type of edit or the role of the user
the last edit is ignored or offered for resolution to the last editor
some types of edits might be 'merged' automatically
etc.
Another nice and simple strategy is to disallow all edits whilst offline.

There are 2 things you want to protect / authenticate
That the client app is authorized to use the service
That the user is authorized to access personal data
App authentication
A mobile application is an untrusted client. Even if you gave nobody access to the app source you must expect that any kind of authorization secret or mechanism is unsafe and can come from a hacked app or other malicious tool that emulates the behaviour of your apps.
For authenticating the app, all you can do is to have a client id, but not a client secret. E.g.
http://service.com/rest?client_id=android
Reply method(String client_id) {
if (!client_id in ["andoid", "ios"])
return Unauthorized();
}
You can change that schema to something a little harder to guess but anything you do boils down to the same security level.
User authentication
Protecting user data is crucial and luckily possible. The key difference is that the secret is not statically hardcoded into the app, it is only known to the user.
One "easy" way to authenticate users is to use other accounts they have. Schemas like http://openid.net/connect/faq/ allow you to do exactly that.
You basically delegate the authentication to some other service. and get a (per service) unique user id which you can use in your code as key to all user data. An attacker can not forge this since your server can authenticate that the token is valid by asking another service. Looks roughly like
http://service.com/rest?client_id=android&user_token=aasjkbn9nah9z23&user_auth_service=facebook
Reply method(String client_id, user_token, user_auth_service) {
if (!client_id in ["andoid", "ios"])
return Unauthorized();
authenticated_user_id = user_auth_service.getUserIdOrFail(user_token);
accessDatabase(authenticated_user_id);
}
An attacker can still use your service from some evil app but there is no way to access accounts he has no access to anyways.
And if you hardcode access tokens into the app, you better don't expire them or make sure to handle that case specifically in the app somehow. There are always users with outdated app versions.

Related

Safely storing refresh tokens in Java application

Let's say we have a very simple Java application, that edits resources on remote servers, that it authenticates with using Access Tokens. Application always uses the same identity, so it is always using the same client id, secret and refresh token to obtain access token.
The whole authentication process is supposed to go through without user intervention and app should perform actions automatically triggered by the user from another application. The other app is sending HTTP requests, but the whole thing would only be accessed in internal network and there would be no "legal" way to access it outside of it.
Is there a way to keep this data (refresh token, client id, secret...) securely within my application?
I have seen similar questions, but they all talked about websites and cookies, but this is supposed to happen under the hood, without any frontend etc. so I don't think those apply to my issue.
Edit: the application will be deployed on an internal server so it's not a Desktop solution. Basically there is an internal app that will send HTTP request to mine, triggering edit on a remote server that is outside of the internal network.
It is not a good idea to store client secrets, access tokens, refresh tokens etc in persistence storage unless it is stored in a secret store (like Vault). But there are other options.
If you are using Spring then you can use Spring OAuth2RestTemplate or else you can write something similar by looking at the code.
It acquires or renews an access token transparently and caches to avoid round trips to Authorization server.
The simplest option is to use memory storage, but if that diesn't work because you need to deal with restarts etc, operating systems provide per-user secure storage. This is a model sometimes used by OAuth desktop or console clients:
Credential Manager on Windows
Keychain on macOS
Passwords and Keys on Linux
It would require some native interop to interact with these credential stores, via use of a library such as java-keytar.
DESKTOP EXAMPLE
For something to compare against see these resources of mine:
Node.js desktop keytar code
This blog post has some related screenshots towards the end

How can I hide my database information in Java?

I'm trying to figure out database security in Java. Like video games, desktop app and others that uses database in its code and how they can store their password in it.
Here's an example:
There's an application that uses MySQL database for storing users data and their information.
A user is registered and logged into our app. He has 0 coin in start. He bought 100 coin from shop and his coin data changed to 100. During the steps that I mention, he always use database for insert and update his data.
In a nutshell, how can I hide my database information (username and maybe IP?) in my Java code?
In addition, I've searched a while and found that you can send web request for information, but if anyone finds the code of request, they also can make their program and use same request as my app. So, I cannot figure this out.
Usually, the database is in a server that you controls, and you provide an API to make requests.
In these requests there's no information about database username or password, that should be on your server.
Then, you need to protect that connection. Normally, yo do that with authentication and authorization. You need to provide username and passwords to your users, and that is present in any request they do to your server. Also, you need to make controls in your server to control what can do each user (control that a user cannot perform any query they want).
A common way to do this is using federated authentication and authorization, with protocols like OAuth2.0 or OpenID.
Also, you need to make sure that you use HTTPS, or attackers could capture the traffic and extract all the request information.
Short answer: you never talk from the Front End (UI, mobile application, whatever) to the Database.
Usually Frontend talks to some backend server - an entry point to the backend word, a gateway (there is indeed such a term). From that point, the request can be routed to another server, or be processed in the same server (depending on the application, its complexity, architecture, etc) and only after that the information should be stored in the database (or queried from the database and returned back to the end user).
Only the gateway is exposed to the "outer word", all the backend services and of course the database should be protected from the accidental/malicious access at different levels:
at the level of network so that it will be physically impossible to connect to it if you're not making a connection from one of the backed servers
at the level of application security - so that it will be impossible to connect to the database without appropriate credentials (username, password, etc). Note this are not the same Username/password that the end user must know in order to login to the application, these are the data about the user, it has nothing to do with the user / password required to connect to the database.
The answer to your specific question is to use Java's "secret storage" features. This question may be a starting point.
The wider point is - please do not make a MySQL database directly accessible from the internet if that's what you're thinking. The security of such a solution would require specialist skills and your question suggests you don't have those skills...
If your application runs outside a local area network (and even if it runs inside the network), you probably want to put a central service layer in place - and API - to handle requests from your client applications. In this case, you still need authentication - you don't want to allow unauthenticated users to add, remove or spend your coins. Most API frameworks have out-of-the-box solutions for this.

How to properly access an SQL DB from Android securely

I'm in in process of looking to create an Android app; security is obviously the most important thing to keep in mind.
What is the best-practice for authenticating a user and handling business logic (scenario below).
For example, the current design would facilitate the permissions based on the user's login. When a user logs in and successfully authenticates, their Username and Password are stored in session variables. When the user attempts to request a resource that requires a certain permission to view, as part of the process for accessing the resource their Username and Password is sent up to the intermediary Web Service, if this authenticates with the correct permission-set the resource is then accessible.
Is this a reasonable way of operating an Android application or is there a better solution to handling this?
Thanks.
Presumably you're referring to building some sort of web API such as REST API that the Android App would send requests to and the API performs the database actions.
I wouldn't send the username/password combo for every request that tends to be bad practice. You send the user/password combo once to authenticate and the authentication returns some sort of token and this token is then sent in every request and is validated on the API side to ensure it is a valid session token. You could either roll this yourself or use some sort of Single Sign On (SSO) solution such as Google Sign on for example or OAUTH is a common authentication mechanism. Maybe https://oauth.net/ will help.

How to securely store credentials for external service

I'm developing an budgeting application that uses a set of tokens and secret keys to access an external financial service, where a token-secret pair map to a single account. In this system, a user can have multiple accounts and therefore multiple sets of token-secret pairs. The token and secret can be used to access the transactions for an account, which means that the token-secret pairs should be securely stored (and be guarded against nefarious access or tampering). Although these pairs should be securely stored, the external financial service API requires the token and secret in plaintext.
What is a secure technique for storing these credentials at rest but providing the external service API with the original, plaintext credentials?
My application is a REST-based Spring Boot application written in Java 9+. Although there have been other answers I've seen on this topic, many of them are specific to Android and use Android security techniques (as are thus not applicable to my application). This application also uses Spring Data MonogDB to store other non-sensitive information, but if another technology is required for satisfying the above security requirements, I am open to suggestions.
This is not a problem that can be solved inside Java.
The token and secret can be used to access the transactions for an account, which means that the token-secret pairs should be securely stored (and be guarded against nefarious access or tampering).
The fundamental issue is who you are securing this against:
If you are trying to secure it against the people who manage the platform, it is pretty much unsolvable1.
If you are trying to secure it against "ordinary" (i.e. non-privileged) users, then you can either rely on ordinary file system security (plus standard service "hardening"), or you can use something like a Spring Vault or a Hardware Security Module if local file system security is insufficient2.
If you are trying to secure against a hacker who might be able to acquire the privilege of a full administrator, this is probably unsolvable too. (Though a hacker may need to be sophisticated ... )
Note that you can do things like saving the secrets in a Java keystore, but in order to do that the JVM needs the secret key to the keystore in order to get the secret. And where do you store that secret?
Aside:
... many of them are specific to Android and use Android security techniques (as are thus not applicable to my application).
Those techniques typically assume that the platform itself is secure, and / or that it hasn't been "rooted" by the user.
1 - So, if your goal is to embed some secrets in an app that you give to a client to use ... give up. If that problem was solvable, priracy of software, music, videos, etcetera would have a simple and reliable technological solution. Clearly ... it hasn't.
2 - For a lot of purposes, it isn't sufficient. However, the decision should be based on an assessment the risks, and balancing risks versus the cost / severity of the consequences of security failure.

Google Cloud Endpoints limitations... any proposed solutions?

Am I correct in thinking that the goodness of Cloud Endpoints comes with the following limitations:
The REST Api cannot be deployed to a custom domain (it'll remain on appspot.com).
The only authentication supported is OAuth against Google accounts.
Corollary: it isn't currently possible to create a user login/session-tracking mechanism that is Google-accounts-agnostic (e.g., with email as username and a password).
Is there any plan to do away with these limitations and if so, what is the ETA?
Taking these item by item:
Currently, yes this is still the case. Keep in mind, our initial release is targeted at a same-party use-case, where the domain you're serving from basically doesn't matter (it's not user/developer-facing). If you want to use your API to drive a website, you can use your custom domain to have your user-facing content, and still make requests to your appspot domain using CORS. If you're building a mobile app, no one sees the domain at all.
Built-in support (i.e. using the User object) is limited to Google accounts, but you're free to build your own authentication scheme by checking the OAuth headers (or email/password if you must...)
(From the comments, regarding GA status). Endpoints is now GA.
(From the comments, regarding public APIs). Your APIs must be public, but you can limit the clients that can make requests. If you want to make a secret API, i.e. the existence of the API must itself be protected, that's not currently supported. I'd be curious to hear how popular a request this is, but I suspect it's not a blocker for most people.

Categories

Resources