Is there a way to connect to a remote instance of MySQL without exposing MySQL credentials by using Java decompiler ?
If a desktop application connects to a MySQL Server, should you assign a read only access to user to access it? Is this secure enough?
If you find yourself asking these questions then it is probably time to implement some delegated authorization. Instead of the user accessing MySQL directly from your desktop app, create a thin server layer with each user assigned a set of credentials to access. All access to the database will be mediated through this server, which will be responsible for securing the DB and ensuring only data relevant to each user is actually given to them.
if your concern is to avoid password decompilation you could obfuscate your app..
you can use a read-only credential in your app, but this wouldn't prevent de compilation (however, if de compiled the user won't be able to change any data, this would be one way).
you could, use a custom class loader to load a class from the network (this class would contain the credentials)
none of the above techniques will prevent a well experienced user from de compiling and getting their hands on the credentials.
Related
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
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.
We have run into a requirement to encrypt certain sensitive data before storing it in a PostgreSQL database. Our application is a Spring app running on top of Tomcat. We need to store the keys so that our web app can encrypt data before inserting it and decrypt data after retrieving it.
We would like to avoid storing this type of thing in our config files (or files that are filtered by Maven) since those files are checked into source control and readable by anyone with access. We seem to have the same issue with database credentials but it looks like JNDI datasources might solve those.
Are there best practices for this when using Tomcat? Things like environment variables might work but would be cumbersome to maintain.
EDIT: To clarify, we're trying to prevent sensitive data loss due to unauthorized access to the actual database file. Our db lives on a different physical box from our app server so we feel comfortable keeping the keys on the server that the application server lives on.
As far as I have seen, all the best practices around credentials optimize ease-of-use (for the operations team) and code simplification (for the development team), rather than optimize for security. This is very disappointing.
I would state the requirement as: Do not ever store any credentials or encryption keys in an unencrypted form, whether embedded in properties/config files, source code, or files managed separately from the application.
Some effects of this requirement:
JNDI data sources do not work for DB credentials, because the configuration of the JNDI data source resides in a configuration file in the container.
Passwords/passphrases for encryption/decryption (e.g., for the data in a database) cannot reside in the code or a properties file.
You must implement a way for the operations team to pass the secrets to the application as it is instantiated.
How might you design a system to meet this requirement?
Store all of your secrets in an encrypted file in a centralized location (e.g., in Amazon S3 or a Hardware Security Module). The passphrase/credentials to read this encrypted data must never be stored digitally - it is provided (e.g., in the body of a POST) when the app spins up. In addition to the passphrase to the secrets file, you may also need to dynamically provide credentials to get access to the file itself.
When the application receives the passphrase to the secrets file, it cracks it open and initializes it's internals (e.g., create DB data sources, initialize the encryption services, etc.).
You don't need encryption. You need access control.
Best practice? Yes. Cheap? No:
Don't use a single web server user account to log in to the db. This allows privilege escalation and data theft via SQL Injection. Use a unique connection per user. This kills connection pooling and allows maybe 500 simultaneous users max per db box.
Use a database that supports Row Level Security and Column Level Security. Right now, this is just Oracle. PG9.5 will have it. You can mimic it in 9.4
Put the db in its own network zone. Only the web server can connect.
Use a DAM (database activity monitor) to look for bad queries in and too much data out
A guide: https://securosis.com/assets/library/reports/Securosis_Understanding_DBEncryption.V_.1_.pdf
I'm looking for a way to open a JDBC connection without specifying my database login and password in plain text, as the application will be distributed and any Java decompiler would reveal them, allowing the users to access the database easily.
Is there any way to encrypt them, or store them somewhere else?
Looks like you want to let Android application talk to your database directly? Don't do that. It's a major security flaw. No matter how you encrypt your credential, you have to reveal your plain text somewhere during the execution of the program, and anyone with a debugger can see that. The correct way is to have use an API on your web service and call that API from client. All database transaction should happen in a trusted intranet.
Why would you want to do this? Generally the business side of your application would have this info and connect to MySQL. There, a user does not have access to any code. Then you create an endpoint that actually is accessible to the public. There you can worry about passing username and password stuff to the business logic, which again, actually has direct access to your database.
Basically, do not open a jdbc connection anywhere but your server side. Its a security measure.
I have a plain Java application which is supposed to connect to the database. I don't want to store database connection url and username/password in a properties file or hardcode it in application. What is a common way to solve this problem? How a Java application can connect to database without revealing username/password?
I'm a .NET dev, but I've run into the exact same situation.
Last year I was working at a company that had to be PCI compliant to store credit card data, so security was a big deal. The URL/login data has to exist somewhere. The most common method I've seen for securing it is with encryption. I don't know about Java in particular, but .NET has several encryption namespaces in the core Framework. We used these to encrypt the database logins.
You still have a potential security vulnerability, which are the encryption keys used to encrypt/decrypt the data. We used the PCI "compensating controls" method here. Access to the keys is restricted to "key management" role. We also tracked access of the key itself so that there was a record of all user-initiated and system-initiated access. No one user had access to these logs, so there could be no covering of tracks by a single user. These overlapping security methods essentially create a situation where nothing less than a coordiated conspiracy between multiple administrators is required to put the data in jeopardy.
If you aren't willing to store it, you have to prompt for it. You could encrypt the password, but then you have to have a key to decrypt it and you are stuck in the same problem.
One of the common solutions to this problem for server based applications is to store the username and password in a file that has user permissions set in such a way that only the executing user of the application/service can read its contents.
For example, you run your application as user foo-service and it inherits all of the access privileges of the foo-service user. The file containing the username and password is only readable by that user. You read the value from the file and connect to the database as normal.
Possible problems with this approach:
The superuser of this machine may be able to get the password to the database.
An attacker who has penetrated your application security can get access to the database credentials.
The above problems are normally mitigated by tuning the access privileges for the application to the database and the network. Nearly any other solution you come up will get you into a chicken-and-egg problem because you are basically trying to hide something from itself.
The best way would be to store the information as a configured data source in the JNDI context of your application server. You can then use the facilities of the application server to configure data sources at deployment time. All the application has to do is look up the appropriate JNDI name at runtime and use that. This is a common pattern for Java web applications.
Use web services to separate your application from the server doing the database access. Sign your web application and then only allow a properly signed application to call the web services server.
You can try to load a file using system properties.
-Dapplication.configuration=application.properties.
When the property file is not passed then the you should use default file with default config.
When the file exists you override the defaults with the values provided from configuration.
java -Dlog4j.configuration=file:/log4j.properties -Dapplication.configuration=file:/live-conf.conf -jar app.jar "applicationarg1" "applicationarg1"
More sources to follow:
https://docs.oracle.com/javase/tutorial/essential/environment/properties.html
How to override system properties:
-Dproperty=value
Set a system property value. If value is a string that contains spaces, you must enclose the string in double quotes:
http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html