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
Related
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.
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.
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.
I have two Java wepapps potentially on different domains/servers using Spring Security for authentication. The first is handling authentication locally storing users in the application database. For the second, I would like to authenticate users using the same users accounts than the first webapp with single sign on (if a user is authenticated in the first webapp, it shouldn't have to enter his info again in the second).
I identified three potential ways to do this but it doesn't seem very straightforward:
Shared cookies: Using a shared session cookie and the same database for the two applications. It seem relatively easy to do but the two webapps need to be on the same domain which isn't necessarily the case for my applications.
Directory service: Using a central directory service (LDAP) which would be used by the two webapps to handle authentication. It seem pretty heavy to implement and the users can't be stored in the first webapp database anymore. The existing users accounts would need to be migrated into the LDAP and it would not be possible to create new users using the first webapp.
OAuth: It seem to be be possible to make the first webapp handle external authentications requests by providing an OAuth api (like Google sign on kind of service). That would allow the second webapp to use this api to authenticate the users, but I'm not sure that the signin process would be totally transparent to handle single sign on. It doesn't seem very easy to implement either, as it would necessitate the development of a complete OAuth api in the first webapp.
I also looked at this service https://auth0.com that seem to provide an authentication api that can be interfaced with an external database, but I'm not sure that it can be interfaced with Spring Security and it also mandate the use of an online solution which isn't ideal. I'm not sure that it would handle single sign on either, only shared accounts.
Is there any other way to handle this use case that would be more straightforward?
CAS is a good candidate indeed as a SSO system for your need and it has several CAS clients for Spring Security. You can try for free a CAS server v4.0 at CAS in the cloud: http://www.casinthecloud.com...
As you mentioned, a shared cookie won't work across domains.
LDAP would give you shared credentials (single name/pw works for both systems), but not single sign on, and you notice you'll have provisioning issues.
Not knowing anything about Spring Security, odds are high you won't find a painless solution to this. Integrating SSO is fraught with workflow issues (user provisioning, password recovery, user profile maintenance, etc.)
We had a classic DB managed authentication scheme. Later, when we added LDAP support, we added the capability for "auto-provisioning". This basically consisted of having the application pull down the relevant demographics from the LDAP store during login, and simply updating fields each time user logged in. If the user didn't exist, we'd create one on the fly.
This worked well, because the rest of the application had no awareness of LDAP. It simply worked with the user profile we managed already and if it needed something from the DB, the data was there.
Later, when we integrated SSO, we just leveraged the existing LDAP logic to pull from the SSO server and do the same thing.
This workflow helped a lot with provisioning and management. We could maintained the authoritative source (LDAP, SSO), and the app just kept up. What it hindered was local editing of the user profile, so we simply disabled that. Let them view the profile, but they could go to the other systems portal for management. Inelegant, but it's a rare use case anyway, so we just muddled through it. We eventually worked out two way pushing and replication, etc. but it's a real pain if you don't need it.
You can look here if you want an overview of how to do cross domain SSO: Cross Domain Login - How to login a user automatically when transferred from one domain to another
For our SSO, we use SAML v2 Web Profile, but we ended up writing our most of our own code to pull it off.
But, bottom line, no matter what the web sites say, integrating this is non-trivial. The edge cases and workflow/help desk issues that surround it are legion. And it can be a bear to debug.
I keep on facing this question from my manager how SSO will work if client disable cookies but I don't have any answer. We are currently using JOSSO for single sign on. Do we have any open source framework which support single sign on without using cooking mechanism.
In the absence of cookies, you're going to have to embed some parameter in each url request. e.g. after logging in you assign some arbitrary id to a user and embed that in every link such as http://mydomain.com/main?sessionid=123422234235235. It could get pretty messy since every link would have to be fixed up before it went out the door which slows down your content. It also has security, logging and session history implications which are not such a huge deal when the state is in a cookie.
It may be simpler to do a simple cookie test on logged in users and send them off to an error page if they do not have cookies enabled.
The CAS project passes a "ticket" from the sign on server to the consuming application as a url query parameter, the consuming app then makes a back channel request back to the sign on server to validate the ticket's authenticity. This negates the need for cookies and therefore works across domains however it is a bit "chatty"
Another arguably more robust solution is to use a product based on SAML which is an industry standard for cross domain single sign on. There are a couple of open source products out there which use SAML and CAS itself has a SAML extension however they are typically quite complex to setup. Cloudseal is also based on SAML and is much simpler to use. The Cloudseal platform itself is delivered as a managed service but all the client libraries are open source
Of course with all these solutions you are simply passing a security context from one server to another, the consuming application will no doubt create it's own local session so you would then need to use URL rewriting instead of cookies
Disclaimer: I work for Cloudseal :)