36

Is it a good idea to keep the username and password of database in a xml file and import it into security file of the spring security ? is there any better option? If I need to encrypt the password how to do it and how to find the encrypted version of password on phpMyAdmin? MySQL

login-service.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

   <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/muDB" />
    <property name="username" value="jack" />
    <property name="password" value="alex123432" />
   </bean>

</beans>

myproject-security.xml

      ....
    <beans:import resource='login-service.xml'/> 
      ....

PLEASE NOTE: As all user related passwords are already encrypted, I am only intended to hide the password of the DATABASE itself not table columns. This password would be used by my application to get connected to the database.

Jack
  • 6,430
  • 27
  • 80
  • 151
  • 2
    @user3580294 then how to encrypt the password of database? or where to keep them? – Jack May 16 '14 at 06:23
  • 2
    It is the database password not those password fields in the tables. is the procedure the same? – Jack May 16 '14 at 06:28
  • Even then, you don't want to store passwords in the clear or encrypt them. I believe the procedure would be the same or at least similar. – awksp May 16 '14 at 06:29
  • 1
    does that mean I should encrypt them and copy the encrypted value in the password part of my code and mysql!!! – Jack May 16 '14 at 06:31
  • Is this a password that a user is inputting or is going to be hardcoded into the application for the application to use to connect? – awksp May 16 '14 at 06:32
  • it will be used by the application – Jack May 16 '14 at 06:33
  • So no user interaction at all? – awksp May 16 '14 at 06:34
  • PLEASE NOTE: I am intended to hide the password of the DATABASE itself not table columns. This password would be used by my application to get connected to the database. – Jack May 16 '14 at 06:35
  • I'm aware of that. What I'm worried about is that having cleartext username/password for authentication allows *anyone* to get access, which you probably don't want. I originally thought you were going to have the user authenticate, but seeing as that isn't the case, I can't see how you expect to secure your program given that you have to load the cleartext password at some point. – awksp May 16 '14 at 06:37
  • Thanks for your concern but all user related passwords are encrypted. – Jack May 16 '14 at 06:38
  • Encrypted or hashed? So what you're looking for is a way for your applications to authenticate themselves? – awksp May 16 '14 at 06:39
  • I am using bcrypt algorithm for them. – Jack May 16 '14 at 06:40
  • Oh OK. That's a hash, by the way. But yeah, nothing more to say... Sorry for wasting your time – awksp May 16 '14 at 06:41
  • If any attacker has access to the java process, any efforts are futile. Oddly enough encrypt schemes or even user input on start-up do no provide much at all. There is little to be done vs memory snapshots. – bestsss May 22 '14 at 12:35
  • 2
    @user3580294 It's not possible to hash a password that needs to be utilized for plain-text (as in to *connect* to a database) - and it's no better to send a hash as a plain-text challenge. – user2864740 May 22 '14 at 13:48
  • This is the old thread but it can be really helpful as it really addresses the pain http://stackoverflow.com/questions/97984/how-to-secure-database-passwords-in-php – Sunil May 25 '14 at 13:22

9 Answers9

48

First of all, you should be aware that no matter what you do, if an attacker gains access to your server files, he will be able to steal the password.

If you use an app server's datasource then you just move the location of the plaintext password to a different file.

If you use some form of encryption to avoid storing a plaintext password your app will still have to decrypt it with another password which it will already have. If an attacker goes to great lengths to gain access to your system you can be fairly confident that he will know that too. What you are doing is obfuscating (and gaining a false sense of security) rather than actually securing it.

A more secure solution is for a user to provide the password (or a password to decrypt the DB password) during your app's startup, but that will make administration really difficult. And if you are already paranoid (the good security kind, not the crazy kind) that someone has access to your server, you should consider that the DB password will reside in the system memory.

Other than that, keep your password in your configuration file (which you can be fairly confident that the server won't show to the outside world), lock down your system and give the database user only the minimum permissions required.

jeconom
  • 774
  • 4
  • 4
  • 2
    great thanks, but what do you mean by configuration files? would you give me an example – Jack May 21 '14 at 23:48
  • That depends on your design. If you're using tomcat you can define a datasource as BartekM suggested. In that case you would define the actual DB properties in context.xml, as defined here (Step 3):https://confluence.atlassian.com/display/DOC/Configuring+a+MySQL+Datasource+in+Apache+Tomcat – jeconom May 22 '14 at 06:25
  • 3
    *The only secure solution is for a user to provide the password (or a password to decrypt the DB password) during your app's startup, but that will make administration really difficult.* ==> false, if you have access to the system, memory snapshots are trivial for java. – bestsss May 22 '14 at 12:32
  • 1
    @bestsss what are the memory snapshots? would you please give me an example? – Jack May 22 '14 at 23:06
  • 2
    It's a dump of the memory contents of your application. You can analyze it to find to find the value of every variable. See here: http://docs.oracle.com/javase/6/docs/technotes/tools/share/jmap.html – jeconom May 23 '14 at 07:36
  • 3
    So many people assuming that the database is on the same server as the application, and that it's only holding data for this application... Ever worked with a company that bought a large Oracle install? Consider that such a password will be checked in and distributed to N developer desktops, so hack a dev desktop and you get the credentials to talk to the database without ever needing to hack the application server. Never mind that one probably wants to run the application in dev/qa/production environments which should have different passwords and possibly different users too. – Gus May 14 '16 at 23:48
  • @jeconom sorry that I'm commenting so late after your initial comment ^^. But this would only be problematic until once has established the connection right ? Using a secure string that erases the password from memory after t he connect isn't best practice ? And if no, why ? – AF_cpp May 03 '22 at 09:32
7

One option is to use Jasypt with it's Spring integration in order to be able to store the usename/password as properties in a regular properties file but in an encrypted form. Jasypt will transparently take care of the decryption

geoand
  • 60,071
  • 24
  • 172
  • 190
7

Having passwords in configuration realy sucks and there is no silver bullet for it. However this solution is complient with most security bla-bla-bla. On top it will also obfuscate the credentials in your SCM.

PropertyPlaceholderConfigurer:

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class EncryptedPropertyPlacementConfigurer extends PropertyPlaceholderConfigurer
{
    /** algorithm used for encrpytion and decryption */
    private static final String ALGORITHM = "PBEWithMD5AndDES";

    /** 8-byte Salt. */
    private static final byte[] SALT = { ... };

    /** Iteration count. */
    private static final int ITERATION_COUNT = 19;

    /** Stores parameter specification. */
    private static final AlgorithmParameterSpec PARAM_SPEC = new PBEParameterSpec(SALT, ITERATION_COUNT);

    //All properties starting with !! will be decrypted.
    private static final String ENCRYPTIGION_LEADIN = "!!";

    public static class EncrypterException extends RuntimeException
    {
        private static final long serialVersionUID = -7336009350594115318L;

        public EncrypterException(final String message, final Throwable cause)
        {
            super(message, cause);
        }

        public EncrypterException(final String message)
        {
            super(message);
        }
    }

    private static String decrypt(final String passPhrase, final String message)
    {
        // Create the key
        final KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT);
        SecretKey key;
        try
        {
            key = SecretKeyFactory.getInstance(ALGORITHM).generateSecret(keySpec);
        }
        catch (final Exception e)
        {
            throw new EncrypterException("Error setting up encryption details.", e);
        }

        if (!Base64.isBase64(message))
        {
            throw new EncrypterException("Message is not a valid base64 message.");
        }

        final String result;
        try
        {
            final Cipher cipher = Cipher.getInstance(ALGORITHM);

            cipher.init(Cipher.DECRYPT_MODE, key, PARAM_SPEC);

            final byte[] dec = Base64.decodeBase64(message);

            result = new String(cipher.doFinal(dec), "UTF-8");
        }
        catch (final Exception e)
        {
            throw new EncrypterException("Error decrypting content.", e);
        }

        return result;
    }

    @Override
    protected String convertPropertyValue(final String originalValue)
    {
        if (StringUtils.isNotBlank(originalValue) && originalValue.startsWith(ENCRYPTIGION_LEADIN))
        {
            return decrypt("<Your magic password>", originalValue.substring(2));
        }
        return super.convertPropertyValue(originalValue);
    }

}

Your Bean:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">


    <bean id="propertyPlaceholderConfigurer" class="...EncryptedPropertyPlacementConfigurer ">
        <property name="location" value="classpath:/spring.properties" />
        <property name="ignoreResourceNotFound" value="true" />
    </bean>

   <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="${jdbc.driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
   </bean>
</beans>

Your Property-File:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/muDB
jdbc.user=!!ar7CWlcL8eI=
jdbc.password=!!ar7CWlcL8eI=

Note: If you use the unlimited JCE Policy, you can also use better encryption algorithm but since we do nothing more than obfuscation, this will do the trick and won't let you end up with debugging sessions.

Update:

You can use this to generate your password:

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;

public class Main
{

    private static class DesEncrypter
    {
        /** algorithm used for encrpytion and decryption */
        private static final String ALGORITHM = "PBEWithMD5AndDES";

        /** 8-byte Salt. */
        private static final byte[] SALT = { <You salt> };

        /** Iteration count. */
        private static final int ITERATION_COUNT = 19;

        /** Stores parameter specification. */
        private static final AlgorithmParameterSpec PARAM_SPEC = new PBEParameterSpec(
            SALT, ITERATION_COUNT);

        /** Key specification. */
        private final KeySpec keySpec;

        /** Secret key. */
        private final SecretKey key;

        public DesEncrypter(final String passPhrase)
        {
            // Create the key
            keySpec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT);
            try
            {
                key = SecretKeyFactory.getInstance(ALGORITHM).generateSecret(keySpec);
            }
            catch (final Exception ex)
            {
                throw new RuntimeException("Could not create DesEncrypter: " + ex.getMessage(), ex);
            }
        }

        public final String encrypt(final String message)
        {
            try
            {
                // Create cipher instance
                final Cipher cipher = Cipher.getInstance(ALGORITHM);
                // Initialize cipher
                cipher.init(Cipher.ENCRYPT_MODE, key, PARAM_SPEC);
                // Encode string
                final byte[] enc = cipher.doFinal(message.getBytes("UTF8"));
                // Encode bytes to base64 to get a string
                return Base64.encodeBase64String(enc);
            }
            catch (final Exception ex)
            {
                throw new RuntimeException("Error encrypting message.", ex);
            }
        }
    }

    public static void main(final String[] args)
    {
        if (args.length == 2)
        {
            System.out.println("!!" + new DesEncrypter(args[0]).encrypt(args[1]));
        }
    }
}
Hannes
  • 2,018
  • 25
  • 32
4

You can hold it on application server and get by jndi name.

For example if you use any jpa implementation like hibernate/eclipse-link you can define it as follow

spring-security.xml

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="dataBase.db"/>
</bean>

persistence.xml

<persistence-unit name="dataBase.db" transaction-type="JTA">
...
    <jta-data-source>java:jboss/datasources/PostgresqlDS</jta-data-source>
...
</persistence-unit>

On application server you have to define conection to database(datasource) in server config file. In Jboss 7 case it is stadalone.xml jboss datasource.

bmlynarczyk
  • 808
  • 10
  • 19
  • 1
    give me an example plz – Jack May 16 '14 at 06:23
  • 1
    great, but where to set the password for the application to use and where to put the encrypted password for db? – Jack May 16 '14 at 06:35
  • Credentials are in datasource on application server. Every j2ee application server has own way to configure it named as datasource. – bmlynarczyk May 16 '14 at 06:38
  • i see, all right I will have a look at my application server, which is tomcat. – Jack May 16 '14 at 06:40
  • 1
    for completeness in the application server, for example Tomcat you define the datasource in the server xml file ie: "" – Paizo May 20 '14 at 15:08
4

Good and old chicken and egg problem.

Is it a good idea to keep the username and password of database in a xml file and import it into security file of the spring security ?

It is a better idea than storing it plain in the source code, but worse than having an enterprise application server handling that for ya (like SAP NetWeaver or Oracle WebLogic).

The good part is that you separate your application from the credentials, allowing for environment specific configuration and OS security restrictions.

Like most of software solutions, it depends. And in your case, it depends on how much "effort" is supposed to be dedicated for that purpose.

Is there any better option?

Even if you are storing the credentials in a file you should at the minimum encode it or if possible encrypt it. But again, this will only "obfuscate" the real password.

For instance, in order to encrypt with a synchronous algorithm you will need a secret key. So where will this secret key be stored? This is circular security which makes the effort to hack the password greater but does not eliminate the risk.

Suggestion 1: Make the file that store the credentials only accessible for the OS admin user and your system user as well so it can read it. Use secret key encryption on top of it. Personally I always go with the AES 256 algorithm.

Suggestion 2: Instead of storing it in a file, ask for the infrastructure team (super OS admins) to send you the encrypted password as a system parameter. Delegate the resposability of the credentials security to the infrastructure team. This is the current approach for AWS Beanstalk integration with RDS.

If you are crazy about security:

  • If you do not trust your infrastructure team you might wanna have the password of the application to be manually entered by a human on the application start-up. You will need to handle the cons of it as well, like always needing a human presence for the start of the application, and horizontal scaling.

  • You might wanna have the password "physically" handled like within a DVD media which has to be inserted on the server by a operational member. As well you will have to handle the access on the device within your OS.

Do not be affraid of talking to your stakeholders about it too. Ask him/them what is the "enough" acceptable and be happy about it.

There will always be a risk when storing credentials.

If I need to encrypt the password how to do it and how to find the encrypted version of password on phpMyAdmin? MySQL

Avoid copying your password around. You should handle the credentials inside your server.

For one solution we made a custom software only accessible by Admins via X11 protocol or console, based only in the Java Crypt API. This software was designed for changing the credentials in a secure way.

The password always transit in secure SSH connections (if remote) or even local accessed, and only between Admins and Server since the permissions were defined that way in the OS.

As for the PhpMyAdmin it has its own way for handling passwords, and you most likely wont be able to integrate both solutions into one without a wide customization effort. Do not store passwords for PhpMyAdmin or any other MySQL client, it will only increase your security risk.

Evandro Pomatti
  • 13,341
  • 16
  • 97
  • 165
1

you can keep in properties file

In my project I have created a database.properties under META-INF in STS IDE

SpringLearner
  • 13,738
  • 20
  • 78
  • 116
  • 1
    Can you expand on how you would then retrieve the properties values in say `context.xml`? (not using `Spring`) – theyuv Nov 02 '16 at 13:11
1

In Rails, I keep the sensitive data in Environment variables in a .env file and add the file to .gitignore. I am not sure if you can do something similar.

"If I need to encrypt the password how to do it and how to find the encrypted version of password on phpMyAdmin"

You could create an encrypted password through something like this:

http://bcrypthashgenerator.apphb.com/

..and then you would know what the password was and you could add the encrypted version to the correct table through phpMyadmin.

Could you just keep the passwords in your local repo, but not deploy them to the remote? I am wondering if you could setup a similar scenario to Rails ENV?

Have you looked at something like this: http://www.jasypt.org/spring3.html

Jordan
  • 1,650
  • 2
  • 18
  • 17
0

As someone else mentioned, if you are storing passwords on the server, there is nothing you can do if attacker gains access to your machine. The only viable alternative is to use SSL connection and certificate-based authentication.

The above method has already been discussed on SO and answer has been provided.

Community
  • 1
  • 1
mindas
  • 26,463
  • 15
  • 97
  • 154
0

Recommended to use Datasource configuration in your App Server. And try to use that using JNDI lookup using context

saysiva
  • 810
  • 1
  • 7
  • 11