Spring Boot how to hide passwords in properties file
You can use Jasypt to encrypt properties, so you could have your property like this:
db.password=ENC(XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=)
Jasypt allows you to encrypt your properties using different algorithms, once you get the encrypted property you put inside the ENC(...)
. For instance, you can encrypt this way through Jasypt using the terminal:
encrypted-pwd$ java -cp ~/.m2/repository/org/jasypt/jasypt/1.9.2/jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="contactspassword" password=supersecretz algorithm=PBEWithMD5AndDES
----ENVIRONMENT-----------------
Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 24.45-b08
----ARGUMENTS-------------------
algorithm: PBEWithMD5AndDES
input: contactspassword
password: supersecretz
----OUTPUT----------------------
XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=
To easily configure it with Spring Boot you can use its starter jasypt-spring-boot-starter with group ID com.github.ulisesbocchio
Keep in mind, that you will need to start your application using the same password you used to encrypt the properties. So, you can start your app this way:
mvn -Djasypt.encryptor.password=supersecretz spring-boot:run
Or using the environment variable (thanks to spring boot relaxed binding):
export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
mvn spring-boot:run
You can check below link for more details:
https://www.ricston.com/blog/encrypting-properties-in-spring-boot-with-jasypt-spring-boot/
To use your encrypted properties in your app just use it as usual, use either method you like (Spring Boot wires the magic, anyway the property must be of course in the classpath):
Using @Value
annotation
@Value("${db.password}")
private String password;
Or using Environment
@Autowired
private Environment environment;
public void doSomething(Environment env) {
System.out.println(env.getProperty("db.password"));
}
Update: for production environment, to avoid exposing the password in the command line, since you can query the processes with ps
, previous commands with history
, etc etc. You could:
- Create a script like this:
touch setEnv.sh
- Edit
setEnv.sh
to export theJASYPT_ENCRYPTOR_PASSWORD
variable#!/bin/bash
export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
- Execute the file with
. setEnv.sh
- Run the app in background with
mvn spring-boot:run &
- Delete the file
setEnv.sh
- Unset the previous environment variable with:
unset JASYPT_ENCRYPTOR_PASSWORD
Securing a password in a properties file
Jasypt provides the org.jasypt.properties.EncryptableProperties class for loading, managing and transparently decrypting encrypted values in .properties files, allowing the mix of both encrypted and not-encrypted values in the same file.
http://www.jasypt.org/encrypting-configuration.html
By using an org.jasypt.properties.EncryptableProperties object, an
application would be able to correctly read and use a .properties file
like this:
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://localhost/reportsdb
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
Note that
the database password is encrypted (in fact, any other property could
also be encrypted, be it related with database configuration or not).How do we read this value? like this:
/*
* First, create (or ask some other component for) the adequate encryptor for
* decrypting the values in our .properties file.
*/
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt"); // could be got from web, env variable...
/*
* Create our EncryptableProperties object and load it the usual way.
*/
Properties props = new EncryptableProperties(encryptor);
props.load(new FileInputStream("/path/to/my/configuration.properties"));
/*
* To get a non-encrypted value, we just get it with getProperty...
*/
String datasourceUsername = props.getProperty("datasource.username");
/*
* ...and to get an encrypted value, we do exactly the same. Decryption will
* be transparently performed behind the scenes.
*/
String datasourcePassword = props.getProperty("datasource.password");
// From now on, datasourcePassword equals "reports_passwd"...
How to hide the password in the command java -Djasypt.encryptor.password=somepassword -jar name.jar
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.
Related Topics
How to Get a Defaulttablemodel Object's Data into a Subclass of Defaulttablemodel
Generic Type Parameter Naming Convention for Java (With Multiple Chars)
Spring Data JPA - "No Property Found for Type" Exception
How to Use Printwriter and File Classes in Java
Error Installing Ant: Ant_Home Is Set Incorrectly
What Does an Exclamation Mark Mean in Java
How to Get My Maven Integration Tests to Run
Changing Names of Parameterized Tests
What Is @Joincolumn and How It Is Used in Hibernate
How to Install the Jdk on Ubuntu Linux
Adding Up Bigdecimals Using Streams
Lambda Expression to Convert Array/List of String to Array/List of Integers
Why Is an Instance Variable of the Superclass Not Overridden by a Subclass
Invalid Thread Access Error with Java Swt
How to Test Void Method with Junit Testing Tools
Throttling Method Calls to M Requests in N Seconds
How to Read Numeric Strings in Excel Cells as String (Not Numbers)