We are using Java + H2 Database in server mode, because we do not want users from accessing database file.
To add more protection to database file, we plan to use AES encryption (add CIPHER=AES to database URL) in case the storage is stolen.
However, each user will also need to supply file protection password when connecting ([file password][space][user password]).
Although users do not have access to database file, knowing the encryption key (file protection password) will make the encryption quite useless.
Any idea to keep the database file secure (encrypted) without exposing file encryption key to users?
Thank you.
There is currently no way to do that within H2.
One solution is to use file system encryption that is independent of H2.
But please note at some point you would have to provide the (database file or file system) password. This could be when starting the server (prompting for the password to be entered manually). Unfortunately, because somebody would have to enter the password, you couldn't fully automate starting the server.
One clever approach I've heard of is to write a simple webservice that blocks all sites but your webapp's server. Use SSL with certificate-based authentication.
This webservice provides the encryption key.
It sounds really stupid since it seems to provide the key without authentication but the certificate-based authentication covers that. It provides encryption of the key during transit (and if you're really paranoid you could use a shared key to wrap the database key). It can only be called from the webapp's server and it's a lot harder to trigger a webservice call than to do SQL injection or even looking at the filesystem.
If your risk model allows it you could even run this webservice on the same box as your webapp.
A second approach, if you have the necessary permissions, is to create a virtual disk. Put the key on the virtual disk.
During startup you mount the virtual disk, read the encryption key, then unmount the virtual disk. In some designs you could drop the operating system permissions that allow you to mount the virtual disk - it would then be literally impossible for an attacker to read the key via your webapp.
This comes from a much older strategy that read sensitive information from a CD-ROM (or even floppy disk). The app would read the key and then eject the media. It works but requires manual intervention to reload the media before the next restart. It also doesn't work in modern environments where servers don't have CD-ROMs, much less floppy drives.
Related
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.
Currently i am dealing with a conceptional issue in my Java - SFTP Client/Server - Setup.
Basically i got a client who sends files to a remote server and stores them there. BUT: You trigger the upload via a jar file on your computer, so anyone could decrypt the jar file and read the clear java file and obtain the credentials for my sftp.
Is there any technology to solve this issue or some workaround you can advise?
Greetings and Thanks!
It is inadvisable to put credentials into a common / shared JAR file. It can't be done securely, and if you need to get the user to replace them they need to download and install a new JAR.
There is no way that you can keep the credentials private from the user. If your credentials need to be used on the user's machine, then it will be possible for the user to extract them, somehow. No matter what you try. (Assuming that they control their machine ....)
Saving credentials encrypted does not protect them from the user. The application needs the decryption key. The user can find / extract that and then recover the credentials.
It is better to issue distinct upload credentials for each user. That way, if one user loses or abuses his credentials you can invalidate them without affecting other users.
If I'm understanding your issue correctly, it is rooted at the fact that your java sources contain your credentials.
First, I highly recommend using jSch library for a great implementation of SSH2.
Regarding your credentials, you can find your answer here.
In short - save your credentials encrypted.
Where should I store credentials for my java application to access third party services?
The credentials are not specific per user on my application. They are for accessing a web service my application is consuming. I know enough not to hard code them into my application, but where and how do I store them? I also assume they will need to be encrypted.
.jar file is best way to store all credentials.
Create interface where store your credentials as a final String
convert interface to jar file
Add that jar file in your build path
Implement this interface where u use credentials, and access String object in which u stored credentials.
Db
.properties file
configuration class with constant
Spring have nice functionality with #Value annotation that can auto-magically inject value from .properties file (under resources folder) with a given key.
I use that because in my case I have different key values in multiple app instances and db would require little more complexity, and furthermore I don't make unnecessary queries to db.
On security basis if attacker can read files on your server than he can easily read your db so that don't play a part here. It can be stored in any file on the system.
On the other hand you can have configuration class with
public static final String SECRET_KEY = "someKey"
To build upon #Zildyan's answer, comments and references to other answers.
There are a few options for where to store:
Database
Properties file
Constant (hard coded)
File system (away from application)
As for how to store:
Depending upon sensitivity. Credentials could be stored in plain text (low sensitivity) or should be encrypted (high sensitivity).
It should also be noted that using a combination of encryption and separating the credentials from the source you would restrict internal access to the credentials.
Some examples
a password stored in plain text may be added to source control and read by anyone with access to the source control.
An encrypted password with decryption code would be easily available to anyone able to run the code.
A plain text file stored on the server may be accessible to anyone with access to the server.
An encrypted file stored on the file system may only be accessible to sys admins and the decryption method available to devs.
The same goes for storing in a database and who has access to that database.
JNDI
Per Wikipedia:
The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that allows Java software clients to discover and look up data and resources (in the form of Java objects) via a name.
Your enterprise likely has a JNDI-compatible directory service established. You would ask the sysadmin to include an entry for your particular credentials.
If you are self-administering, then your Java EE (now Jakarta EE) should have a JNDI-compatible server built-in. Learn to configure it, and add the entry for your particular credentials.
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 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