Ever been worried about credentials (passwords, secrets or access keys) residing in your host’s application configuration files as plain text? Read on how to automatically obfuscate your application’s properties residing in configuration files at a system-context’s level.
My blog post Dead simple Java application configuration already outlined the ease of use of the refcodes-properties
artifact. The refcodes-properties-ext-obfuscation
artifact extends this functionality with obfuscation
features bound to a dedicated system context
.
This means, that you automatically can encrypt specific properties in your properties files which will automatically be decrypted at runtime: The file just reveals the encrypted values for the according properties. Even at runtime the according properties are kept in memory with their encrypted representation and decrypted “on-the-fly” only when actually being retrieved by your application from the properties holding object.
Properties residing in your properties file marked accordingly as “to-be-encrypted” will be encrypted upon the first time your application loads them and written back with their encrypted representation, now being marked as “to-be-decrypted”.
An open door may tempt a saint: Obfuscate!
First of all, some warning words on security: What do I mean with
obfuscation
?
As the encryption and decryption mechanism works without any user interaction, it is your application doing the encryption and decryption by itself. Don’t worry: The refcodes-properties-ext-obfuscation
artifact does not use a hard-coded key for accomplishing this task. Nevertheless, the data must be encrypted and decrypted with some key. We use a symmetric-key algorithm
, as a public-key cryptography
approach would make no sense here. This symmetric-key
must somehow be known by your application. This in turn means that with enough criminal intend and technical skills as well as with direct access to your host, an attacker would be able to decrypt your properties. Therefore I prefer to call this method of securing your properties obfuscation
:
Obfuscating
properties secures against attempts to decrypt your sensitive data in cases where the attacker has stolen your properties file but with no access to your host’s runtime. Byobfuscating
your properties, we close the door so to not to tempt any saints. An attacker though having access to your host may reverse-calculate thesymmetric-key
in use!
Before and after obfuscation
The usage of the refcodes-properties-ext-obfuscation
artifact is quite simple. Before you start your application in question, you have to provide a writable properties file as described in the blog post Dead simple Java application configuration with those values to be obfuscated being prefixed with encrypt:
(“to-be-encrypted”). Using the Java notation for your properties, a property with name secret
to be obfuscated looks as follows: secret=encrypt:this_is_my_secret
. An according properties file may look as follows:
1
2
3
4
port=8080
maxConnections=20
identity=webrunner
secret=encrypt:this_is_my_secret
After the fist execution of your application, the refcodes-properties-ext-obfuscation
artifact identifies the properties to be obfuscated, obfuscates them and writes back the obfuscated properties to the file, with the obfuscated values being prefixed with decrypt:
(“to-be-decrypted”). Using the Java notation for your properties, a property with name secret
being obfuscated looks similar to: secret=decrypt:sOhxXOecKqNOBJm+Uzwx38Y=
. An accordingly obfuscated properties file may look as follows:
1
2
3
4
port=8080
maxConnections=20
identity=webrunner
secret=decrypt:sOhxXOecKqNOBJm+Uzwx38Y=
As we do not use any hard-coded keys, how is key-generation for the
obfuscation
process being accomplished? Therefcodes-properties-ext-obfuscation
artifact knows multiple contexts ofobfuscation
being a combination ofhost
-,user
- and/orapplication
individual properties.
Obfuscation contexts
As obfuscation
is done automatically by the refcodes-properties-ext-obfuscation
artifact, the keys for obfuscation
are generated automatically: These keys are not persisted anywhere, they are calculated from specific properties whenever needed. Moreover, the keys have to be calculated by properties which stay constant for some given context but differ for other manifestations of that context. The contexts supported for obfuscation
are host-individual
, user-individual
and/or application-individual
:
Host-individual-context
The properties used for calculating the obfuscation
key are specific for a dedicated host. The same properties though look different on different hosts. Calculating the key on different hosts results in different keys for each host. Calculating the key on the same host multiple times always results in the same key, independent from the user account running the application as well as from the implementing application itself.
In other words: The configuration is bound to a specific host.
User-individual-context
The properties used for calculating the obfuscation
key are specific for a dedicated user account running your application. The same properties though look different for different users. Calculating the key for different users results in different keys for each user. Calculating the key for the same user multiple times always results in the same key, independent from the host running the application as well as from the implementing application itself.
In other words: The configuration is bound to a specific user.
Application-individual-context
The properties used for calculating the obfuscation
key are specific for a dedicated application. The same properties though look different for different applications. Calculating the key for different applications results in different keys for each application. Calculating the key for the same application multiple times always results in the same key, independent from the host running the application as well as from user account running the application.
In other words: The configuration is bound to a specific application.
Combining contexts
The refcodes-properties-ext-obfuscation
artifact now allows you to use any combination of the above mentioned three levels of obfuscation
: APPLICATION
, USER_APPLICATION
, HOST_USER_APPLICATION
, HOST_APPLICATION
, USER
, HOST_USER
, HOST
. These levels of obfuscation
are defined by the enumeration SystemContext
to be used when constructing your obfuscated properties.
An attacker having access to the host may determine the
host
-,user
- and/orapplication
-specific properties in order to calculate the actual key. Major changes on thehost
, theuser
account or theapplication
itself may result in different keys being calculated!
Getting started
To get up and running, include the following dependency (without the three dots “…”) in your pom.xml
:
1
2
3
4
5
6
7
8
9
<dependencies>
...
<dependency>
<artifactId>refcodes-properties-ext-obfuscation</artifactId>
<groupId>org.refcodes</groupId>
<version>3.3.8</version>
</dependency>
...
</dependencies>
Some basic example, loading and storing properties
A very (very!) basic example may look as below, just loading some Java based properties file using syntactic sugar:
1
2
3
4
5
6
7
8
9
10
11
import static org.refcodes.properties.ext.obfuscation.ObfuscationPropertiesSugar.*;
// ...
public class Foo {
public Foo() throws IOException, ParseException {
ResourcePropertiesBuilder properties = seekFromJavaProperties( "application.properties" );
ObfuscationResourcePropertiesBuilder obfuscateProperties = obfuscate( properties );
obfuscateProperties.put("secret", "encrypt:Hello world!");
obfuscateProperties.flush();
}
// ...
}
In the above example, we load properties from a file called “application.properties
” as described here
(see the ConfigLocator on how the properties file is discovered and where it is to be placed). Then we decorate the properties with a decorator of type ObfuscationResourcePropertiesBuilder
. The actual implementation of this type is the ObfuscationResourcePropertiesBuilderDecorator
class. Specifying a level of obfuscation
would look as follows:
1
2
3
4
5
6
7
8
9
10
11
import static org.refcodes.properties.ext.obfuscation.ObfuscationPropertiesSugar.*;
// ...
public class Foo {
public Foo() throws IOException, ParseException {
ResourcePropertiesBuilder properties = seekFromJavaProperties( "application.properties" );
ObfuscationResourcePropertiesBuilder obfuscateProperties = obfuscate( properties, SystemContext.HOST_USER );
obfuscateProperties.put("secret", "encrypt:Hello world!");
obfuscateProperties.flush();
}
// ...
}
Here, the key generated for obfuscation
is host
- and user
-individual, e.g. different applications executed by the same user on the same host will use the same key, though when being executed by a different user and/or on a different host will result in a different key to be used.
Instead of passing a
SystemContext
value to theobfuscate
method, you might also pass your own individualString
being the secret from which the obfuscation key is being derived.
Under the hood
Above we use syntactic sugar: When invoking obfuscate
, a decorator
is being wrapped around the properties object. We can write the same functionality without the syntactic sugar as follows:
1
2
3
4
5
6
7
8
9
10
11
import org.refcodes.properties.ext.obfuscation.ObfuscationResourcePropertiesBuilderDecorator;
// ...
public class Foo {
public Foo() throws IOException, ParseException {
ResourcePropertiesBuilder properties = ...;
ObfuscationResourcePropertiesBuilder obfuscateProperties = new ObfuscationResourcePropertiesBuilderDecorator( properties, SystemContext.HOST_USER );
obfuscateProperties.put("secret", "encrypt:Hello world!");
obfuscateProperties.flush();
}
// ...
}
Instead of passing a
SystemContext
value to the constructor, you might also pass your own individualString
being the secret from which the obfuscation key is being derived.
Further reading
See the blog post on the refcodes-properties
artifact for further details on the usage of this artifact. Also see the blog posts Dead simple Java application configuration, Automatically obfuscate your Java application’s configuration and All-in-one Java configuration properties at hand. For examples and usage, please take a look at the according Unit-Tests
here. On chaos-based encryption, see also the refcodes-security
artifact and the according Chaos-based encryption blog post.