24

I want to keep encoded password in my below mentioned springApplicationContext.xml

Is there any way to achieve this?

presently I have configured all properties using property-placeholder as shown below but the raw password is still open in my database.properties

springApplicationContext.xml

<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName"><beans:value>${db.driverClassName}</beans:value></beans:property>
        <beans:property name="url"><beans:value>${db.url}</beans:value></beans:property>
        <beans:property name="username"><beans:value>${db.username}</beans:value></beans:property>
        <beans:property name="password"><beans:value>${db.password}</beans:value></beans:property>
</beans:bean>

but actual values are present in my database.properties

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=root

I want something like below:

springApplicationContext.xml (same as above)

<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <beans:property name="driverClassName"><beans:value>${db.driverClassName}</beans:value></beans:property>
        <beans:property name="url"><beans:value>${db.url}</beans:value></beans:property>
        <beans:property name="username"><beans:value>${db.username}</beans:value></beans:property>
        <beans:property name="password"><beans:value>${db.password}</beans:value></beans:property>
</beans:bean>

But password property value should be in encripted format in my database.properties

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=3g6n72ef8x (using any encription method).

and my dataSource internally decrypt the password before making new DB connection.

Highly appreciate for any help/suggestion in this.

Sandy
  • 972
  • 5
  • 15
  • 28
  • The approach you suggested below works fine when you can take an encoded string and decode it directly. But for true encryption, you can't take an encrypted string and just decrypt it: you take a plaintext password, encrypt it, and compare it against the already-encrypted value. For instance, see org.springframework.security.crypto.password.StandardPasswordEncoder which is something like what you would probably use once you move past the base64 encoder. So the question is: how does your DataSource get the actual password to check against the encrypted value of db.password? – Jason Oct 11 '12 at 18:44
  • Actually the requirement was not to keep raw password open in my database.properties file. Hence my CustomDataSource is decoding the encoded value of database.properties file and then using to create new database connection. – Sandy Oct 15 '12 at 07:26
  • 2
    I would argue that a base64 encoded password is essentially the same as a raw password (i.e. not secure), but I guess the semantics of the requirement are for the requirement-makers to decide. – Jason Oct 15 '12 at 12:58
  • related: https://stackoverflow.com/questions/27567139/spring-jdbc-template-how-to-decrypt-password – Rohim Chou Mar 01 '23 at 08:17

5 Answers5

20

Its might be funny that I am answering to my own question. but still I just wanted to tell my solution, others who might have faced same kind of issue..

for simplicity I have used BASE64Encoder & BASE64Decoder. later I will modify my code to use a secure/better encryption/decryption algorithm.

I have encoded my database password(ex: root for my case) by using the below code:

private String encode(String str) {
        BASE64Encoder encoder = new BASE64Encoder();
        str = new String(encoder.encodeBuffer(str.getBytes()));
        return str;
    }

and placed the encoded password in my database.properties file like below:

before

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=root

after

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=cm9vdA==  (Note: encoded 'root' by using BASE64Encoder)

Now I have written a wrapper class for org.apache.commons.dbcp.BasicDataSource and overridden setPassword() method:

import java.io.IOException;
import org.apache.commons.dbcp.BasicDataSource;
import sun.misc.BASE64Decoder;

public class MyCustomBasicDataSource extends BasicDataSource{

    public CustomBasicDataSource() {
        super();
    }

    public synchronized void setPassword(String encodedPassword){
        this.password = decode(encodedPassword);
    }

    private String decode(String password) {
        BASE64Decoder decoder = new BASE64Decoder();
        String decodedPassword = null;
        try {
            decodedPassword = new String(decoder.decodeBuffer(password));
        } catch (IOException e) {
            e.printStackTrace();
        }       
        return decodedPassword;
    }
}

This way I am decoding(BASE64Decoder) the encoded password provided in database.properties

and also modified the class attribute of my dataSource bean mentioned in springApplicationContext.xml file.

<beans:bean id="dataSource" class="edu.config.db.datasource.custom.MyCustomBasicDataSource" destroy-method="close">
    <beans:property name="driverClassName"><beans:value>${db.driverClassName}</beans:value></beans:property>
    <beans:property name="url"><beans:value>${db.url}</beans:value></beans:property>
    <beans:property name="username"><beans:value>${db.username}</beans:value></beans:property>
    <beans:property name="password"><beans:value>${db.password}</beans:value></beans:property>

Thanks.

Sandy
  • 972
  • 5
  • 15
  • 28
  • Don't you need to do super.password =decode(encodedPassword); instead of this.password= decode(encodedPassword); – Ahmad Oct 09 '13 at 11:47
  • 9
    Base64 is not encryption, it's encoding ! While encoding the user name and password with the Base64 algorithm typically makes them unreadable by the naked eye, they are as easily decoded as they are encoded. Security is not the intent of the encoding step. Rather, the intent of the encoding is to encode non-HTTP-compatible characters that may be in the user name or password into those that are HTTP-compatible. – Omar Elfada Sep 09 '15 at 12:49
  • 9
    This solution does a base 64 encoding of the password in your properties file, but it is NOT encrypted! I copy pasted "cm9vdA==" into https://www.base64decode.org and immediately got "root". For the sake of others reading this question and answer, please modify the question to ask "How to use base 64 encoded password" instead of "How to use encrypted password" because this answer definitely is not encrypting it. I don't want other readers to think that encoding is the same as encryption. – Jason Nov 12 '15 at 13:42
10

Create customized PropertyPlaceHolderConfigurer extending Spring PropertyPlaceHolderConfigurer

public class PropertyPlaceholderConfigurer extends
        org.springframework.beans.factory.config.PropertyPlaceholderConfigurer {

    @Override
    protected String convertPropertyValue(final String originalValue) {
        if (originalValue.startwith("SomeText:")) {
            //Apply the decryption logic
            ...
        }
    }
}

You can encrypt the properties and append SomeText:. Use this customized PropertyPlaceHolderConfigurer to load the properties

duffy356
  • 3,678
  • 3
  • 32
  • 47
Sujith
  • 1,127
  • 1
  • 13
  • 20
4

I'd like to look at the larger picture here: why do you want to encrypt values in your properties file? What is your scenario where unauthorized people have access to your properties file?

A usual technique to deal with this larger problem of storing production credentials is to make credentials a part of your environment as opposed to part of your source code. Here are some ways to do this:

  • Placing the properties file (with plaintext passwords) on the classpath of the web server in production, this way access to that password is controlled by access to the production machine.
  • Store properties in web.xml (context-param with param-name), again this file is part of the environment in which you run your code and not distributed with your code - access to that file is controlled by access to the machine.
  • Use JNDI and configure that resource in your application server.
Jason
  • 7,356
  • 4
  • 41
  • 48
  • 1
    I have a similar situation above, and we want encrypted passwords in the properties file, because part of our application is installed on a client's server along with another application of ours. This agent uses the other application's database. We don't want our clients to have access to that application's database. So, there is a scenario where encrypted passwords in property files would be needed. – Brett Slocum Aug 29 '13 at 17:47
  • That's an interesting scenario that I hadn't considered, thanks. – Jason Aug 30 '13 at 12:41
  • It still only gives the appearance and warm fuzzies of security, since any encrypted password could be decrypted eventually by a determined party. But it will stop the casual party, it's probably good enough. – Brett Slocum Aug 30 '13 at 16:40
  • There's another scenario to consider, which is where the application is standalone. I used to work in a company that had a software with exact the same situation as explained above, but 'twas a standalone desktop application =) – Gabriel Câmara Nov 11 '15 at 12:20
3

Create a wrapper class implementing the Datasource interface which delegates it's method calls to the underlying datasource but decrypts the password before doing so.

Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97
  • Thanks Abhinav for suggesting me.. Now I am able to achieve this using a CustomBasicDataSource. – Sandy Oct 11 '12 at 11:51
0

If you are using tomcat connection pool as data source, here is an implementation

http://www.jdev.it/encrypting-passwords-in-tomcat/

Create a class which extends org.apache.tomcat.jdbc.pool.DataSourceFactory and configure it in the server.xml

Update:

The newer way is to use Jasypt: http://www.jasypt.org/encrypting-texts.html

Sujith Nair
  • 367
  • 3
  • 9