Where should I put the credentials: application.properties vs system env variables - java

In my spring boot project, where should I put the credentials to use different services, such as username/password for the database or message queue, or the JWT secret key?
Should I put it in a system env variable? or in application.properties? which one is more secure? considering that both are in plain text?
For JWT token I use the following command in OS to update the value before firing up the server:
export MONEYLIZER_JWT_SECRET_KEY=$(echo -n "somevalue" | openssl sha512 -hmac "somekey")
So it's not always constant. application.properties doesn't give me this flexibility.
What is usually done for commercial services? where should I keep the credentials and settings?

Environment variables are definitely more secure than plain-text in application.properties
Typical Sping-based deployments suffer from configuration being hard
coded into the application properties files of the code repository.
This is great for modularizing your code base so it can be transported
to multiple environments. However it ensures your code also has clear
text passwords, api keys and other data that shouldn't be in a VCS
repo or distributed in any way.
In order to lock down the security of the code base itself we decided
to externalize all the passwords, api keys and other confidential data
from our code base. Spring makes it remarkably easy to do this,
providing the options to specify configuration as environment
variables at boot or specify external application property files to an
init script or CLI call.
veracode blog

Related

How to store secrets of a Spring Boot application in HashiCorp Vault securely?

I've read following tutorial:Vault Configuration
Ok we installed the Vault server and put 2 pairs of secret properties:
$ vault kv put secret/gs-vault-config example.username=demouser example.password=demopassword
$ vault kv put secret/gs-vault-config/cloud example.username=clouduser example.password=cloudpassword
Spring boot application has following properties(bootstrap.properties):
spring.application.name=gs-vault-config
spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
So based on spring.cloud.vault.token application able to read secure properties(name and password) but spring.cloud.vault.token is stored in the insecure place - bootstrap.properties which is stored in the code repository. Could you please explain why it is safe?
P.S.
As we found out it is insecure. How to make it secure ? I understand that there are might be several solutions to make it secure but single simplified example would be enough for me.
Could you please explain why it is safe?
The answer is that it is NOT safe ... if you do it that way. For example, the Spring Vault reference manual says:
"Consider carefully your security requirements. Static token authentication is fine if you want quickly get started with Vault, but a static token is not protected any further. Any disclosure to unintended parties allows Vault use with the associated token roles."
You should either protect your static tokens, or only grant them access to "secrets" in the vault which you are happy to be widely known.
Alternatively, have your application use an authenticated method to generate short-term dynamic tokens.
As I understand initial problem it is bad to store passwords in an application.properties file on Github.
And storing a static Vault token in an application.properties file on Github is equally as bad.
What is the difference ?
There is almost no difference1. This is simply the wrong way to use Vault.
1 - There is a small advantage in that you could invalidate the token if you discover it leaked by accident. But this doesn't mean that it is sensible to publish it deliberately.
So how do you do things securely?
First, you MUST secure the machines where the secrets are going to be used. Even if you are not going to store the actual secrets on disk, you will need to store a different secret (securely) on each of your machines so that they can authenticate themselves to the place where the real secrets are kept.
Here is an example using Chef.
Set up a secure Chef server that holds the configs for your machines; i.e. recipes for all of the things that need to be installed, node descriptions to say what recipes to apply, etc.
When you bootstrap a machine as a node, a keypair is generated for the machine and registered with the Chef server. The keypair is also held on the machine, and has to be held securely.
Then you use the Chef client to run the recipes that install and configure your server.
Note that this relies on having a properly secured system to run the Chef server. It also relies on each of the nodes being sufficiently secure to protect their own keys.
There are other ways to do this, but nothing will work if you cannot secure your host sufficiently.
Storing spring.cloud.vault.token in the application.properties that is checked into VCS (e.g. Git) might compromise all secrets stored in Vault.
The solution is not to store Vault token in application.properties as a plain text. There are several options.
Remove Vault token from application.properties
Simply remove spring.cloud.vault.token from application.properties and instead provide it via system property -Dspring.cloud.vault.token=00000000-0000-0000-0000-000000000000 (when starting the application) or environment variable SPRING_CLOUD_VAULT_TOKEN. Environment variable is especially convenient if you use containers (Docker or Kubernetes).
Store encrypted Vault token in application.properties
You can keep spring.cloud.vault.token property in application.properties if it is encrypted.
Spring Cloud Config supports decrypting properties with values starting with {cipher}:
spring.cloud.vault.token={cipher}encrypted_vault_token
To use properties encryption and decryption you will need the following dependencies (example for Gradle):
implementation 'org.springframework.cloud:spring-cloud-context:2.2.2.RELEASE'
implementation 'org.bouncycastle:bcprov-jdk15on:1.64'
Symmetric encryption
The simplest way to encrypt the properties is to use symmetric encryption.
Come up with a symmetric key (for example s3cr3t).
To encrypt Vault token you can use Spring Boot CLI with Spring Boot Cloud CLI:
curl "https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.2.2.RELEASE/spring-boot-cli-2.2.2.RELEASE-bin.tar.gz" -o spring-boot-cli-bin.tar.gz
tar -xf spring-boot-cli-bin.tar.gz
cd spring-2.2.2.RELEASE
bin/spring install org.springframework.cloud:spring-cloud-cli:2.2.1.RELEASE
bin/spring encrypt 00000000-0000-0000-0000-000000000000 --key s3cr3t
# 507cd1614682535ab8237b448ca73dc74058d3ae9145d63a7381ee67f3046eb1598da6960abdbf2dbf22c47206db5222e45fc74fd6122bc707b61c62f5051e0f
bin/spring decrypt 507cd1614682535ab8237b448ca73dc74058d3ae9145d63a7381ee67f3046eb1598da6960abdbf2dbf22c47206db5222e45fc74fd6122bc707b61c62f5051e0f --key s3cr3t
# 00000000-0000-0000-0000-000000000000
Pass the symmetric key to the application in ENCRYPT_KEY environment variable.
Symmetric encryption key must be never checked into a VCS.
Asymmetric encryption
Consider asymmetric encryption using public and private key pair as a more secure alternative to symmetric encryption.
Instead of a symmetric encryption key you need to generate a keystore (using the keytool utility that comes with the JDK or openssl).
In the bootstrap.properties specify the following properties:
encrypt.keyStore.location
encrypt.keyStore.password
encrypt.keyStore.alias
encrypt.keyStore.type
The keystore has to be mounted at the location specified in encrypt.keyStore.location and never checked into a VCS.
Also, password that unlocks the keystore better to pass in ENCRYPT_KEYSTORE_PASSWORD environment variable.
Read about key management in Spring Cloud Config.
Answering your questions
Could you please explain why it is safe?
It is not safe! Never put a plain secret in source control.
As we found out it is insecure. How to make it secure?
Some ways to increase security:
Use environment variables instead of properties file;
Restrict the access at the network level to the Vault server only to workload servers. This guarantees that nobody outside that network can exchange the token;
Vault works generating real but temporary credentials each time the token is used. Reduce the scope of the real credentials to read-only whenever be possible;
Rotate the token regularly.
Regarding the Spring specifics
The bootstrap properties should contain only non-critical properties. For critical properties, you can pass them to the application using environment variables.
spring.cloud.vault.token = ${SPRING_CLOUD_VAULT_TOKEN}
Summary
The question remains "Who guards the keys?". But the Vault Token serves actually to protect the real sensitive data. In case the vault token is leaked, you can invalidate just the token.
Improve the constraints from where applications can access the vault server and reduce the scope of the real credentials are additional ways to ensure that only the servers that run the application can exchange the tokens by the real credentials and the real credentials have the minimum privilege as possible.

How to hide the password in the command "java -Djasypt.encryptor.password=somepassword -jar name.jar"

I am using Jasypt encryption and specifying the property value within ENC() in the properties file. The decryption password is sent through the command-line argument like this java -Djasypt.encryptor.password=somepassword -jar name.jar. Everything is working fine but the problem is when I search for the running process, it shows the password as well. Is there a way to hide the encryption password as well by read it from somewhere?
I thought of using the environment variables but that could also expose the password as well. So, decided against it.
Update:
There was a solution in another SO post
Spring Boot How to hide passwords in Properties file?
The solution what I followed was to create an environment variable with the name JASYPT_ENCRYPTOR_PASSWORD, execute the command java -jar name.jar and then unset the environment variable. This worked as I intended.
The solution what I followed was to create an environment variable with the name JASYPT_ENCRYPTOR_PASSWORD, execute the command java -jar name.jar and then unset the environment variable. This worked as I intended.
Setting an environment variable, for a short time or not doesn't matter, isn't a good idea. Even the shortest of time can be enough that an attacker can get access to it. There are similar attacks where the name of a temporary file could be predicted and allowed an attacker to create a link with that name to e.g. access the /etc/passwd-file, etc.
The problem exists for a while so there are a couple of solutions out there already, most of which work with a file that contains the password or a key store that is used to do encryption and decryption of sensible data.
If you look e.g. at JBoss they use something called a vault. There is a manual page explaining the single steps. You can recreate all of this for your application or just read the plain text password from a file where you specify the filename e.g. as system property. The file itself must be secured against unauthorized access on the file system level (set the read permission for the owner only) and - if necessary - within your application by setting a SecurityManager that denies access to this file by other classes than the one that is used to read it in. This is common practice with security relevant applications like PGP or OpenSSL.
Jasypt Is the most common and easy way to encrypt application properties .
As mentioned above You can use an environment variable to store the Password for Jasypt encryption or decryption and pass on the variable while running your application as jar .
But the Purpose of vault is bot more different , You can store and encrypt more than required in vault , vault provides you more control in terms of Encryption .
You can update or change values in Run time as well using Vault .
The secrets generated in Vault is bit more dynamic instead of user defined , it completely abstracts the encryption .
Hence it depends on your use case either to use vault or JASYPT . But both are used in Industry widely .
I prefer JASYPT as a developer but as a whole project I use Vault in Prod .
You can definitely use Jasypt to read from EncryptableProperties stored in a properties file using something like this:
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
And then you can retrieve the properties (both encrypted and not) from your program:
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt"); // could be got from web, env variable...
Properties props = new EncryptableProperties(encryptor);
props.load(new FileInputStream("/path/to/my/configuration.properties"));
String datasourceUsername = props.getProperty("datasource.username");
String datasourcePassword = props.getProperty("datasource.password");
Note that in the example above, both the unencrypted and encrypted properties are retrieved the same way, while Jasypt handles the decryption/encryption automatically.
Here's a link to the relevant Jasypt documentation:
http://www.jasypt.org/encrypting-configuration.html
And here's a similar question in SO with more details:
https://stackoverflow.com/a/10307724/236528

Hiding secret key in server OR externalizing application properties

I have some secret api keys for my server and i have to use in my project. But i am not feeling safe to keep in properties file or any physical location in server. Can any one tell me what are possible ways to keep it secret and use wherever it's require in application.
If you are really considered about the passwords you've got, the best way is using HSM (Hardware security module). This way you will be assured that keeping your private key in a secure place is not part of your consideration anymore.
If that is expensive, then you can think of storing your private key in JKS or PKCS12 and choose a strong password.
Generally you are looking for a vault. In PKI you can have a vault to store your secret in it. there are couple of ways I can think of. One of them is HSM as I described above and the other one is following:
For storing your password you need to salt it or store it in another server w/ salt and whenever you need the password, it's better to have a secure connection between your real server and password only stored server to request the password.
Also you can take a look at this project from Hashicorp
https://github.com/hashicorp/vault
There are many options here depending on your actual security requirements.
You've mentioned java and spring boot, so I'll mainly specify solutions related to this technology stack.
Since you're already using Spring Boot, consider spring-cloud-config server.
It has some interesting "encryption" features:
Step 1
Create a Key (public/private pair or shared depending on your requirements)
Specify it when starting the config server (via -- or env variable):
encrypt.key=ABC123ABC123ABC123
Step 2
Encode value of the password by calling a rest request of this server (you do it once)
curl localhost:8888/encrypt -d mysecretdbpassword
>>AZXCASDAZXC341234ZXCASDFedr453
Step 3
In application.properties specify that the value is "encrypted" with a special syntax
The file will be stored on a configuration server and not on the microservice. The
property will look like this
db.password={cipher}AZXCASDAZXC341234ZXCASDFedr453
The property will be kept encrypted in files but decrypted in memory. So the microservice will get a decrypted value.
The documentation is available here. This is by far the fastest way to implement the requirements. You can keep it in a dedicated microservice or embedded into the already-existing application.
In addition, it allows integration with JKS, so its possible to store passwords there.
Complementary/Alternatives
Spring cloud config is also integrated with Hashicorp Vault which can be a good solution for your situation on its own (even without spring boot cloud config).
Yet Another possible solution that comes from Spring Universe is called Spring Vault
Its intended for working with secrets.
I use onboardbase to hide secret i would recommend that they are few other out there to check like doppler
You can setup your application.properties as below
application.properties
secret.key1=${SECRET_KEY1}
secret.key2=${SECRET_KEY2}
While building the application we can pass it as an environment variable
mvn clean install -dSECRET_KEY1=123456 -dSECRET_KEY2=abcdef
We can pass the environment variables in docker as well by using -e SECRET_KEY1=123456

How secure is jasypt?

I have recently made an app that uses jasypt APIs for encryption and decryption of text and Passwords.
My question is, if the hacker also uses or knows about jasypt, would it be possible for him to use the decrypt() method to decrypt my encrypted data?
How do i make sure that another person who's also using jasypt cannot decrypt my data?
I think so. Say you have a Spring Boot application and you have application.properties file with username and password like:
# in application.properties
username=myuser
password=DEC(mypassword)
jasypt.encryptor.password=tester
Once you run jasypt command to encrypt above password, the application.properteis file will be modified and will look like:
# in application.properties
username=myuser
password=ENC(hlyNvWcMld4LeQUkExq3i9QD9i2x8U4c)
jasypt.encryptor.password=tester
If this file goes into a repository like a GitHub or SVN, there is nothing there to prevent malicuous user to take the jasypt.encryptor.password and use it to decrypt the password and endup with its original value mypassword. There is even an online tool for that.
I think the same applies with Spring Cloud Config server where instead of DEC(), END(), {cypher} is being used.
To me, the only way around that is that the application.properties content cannot ever be pushed to a repo. Or that different values are provided for development and production in which case even if you have the jasypt.encryptor.password in the application.properties and that is in GitHub, it is used only for development.
On deployment, the container will provide another password. So, this would be "safe" but still, it disclosed internals about the application. For example, attacker now knows that your application uses jasypt and relies on the correct jasypt.encryptor.password.

Secure JDBC connection

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

Categories

Resources