web-dev-qa-db-fra.com

Où devrais-je conserver les informations d'identification de ma base de données?

Est-ce une bonne idée de conserver le nom d'utilisateur et le mot de passe de la base de données dans un fichier xml et de les importer dans le fichier de sécurité de la sécurité printanière? Y a-t-il une meilleure option? Si j'ai besoin de chiffrer le mot de passe, comment le faire et comment trouver la version chiffrée du mot de passe sur 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'/> 
      ....

VEUILLEZ NOTER: comme tous les mots de passe liés aux utilisateurs sont déjà cryptés, je ne souhaite que masquer le mot de passe de la base de données elle-même, et non des colonnes de table. Ce mot de passe serait utilisé par mon application pour se connecter à la base de données.

19
Jack

Tout d’abord, sachez que peu importe ce que vous faites, si un attaquant obtient l’accès aux fichiers de votre serveur, il pourra voler le mot de passe.

Si vous utilisez la source de données d'un serveur d'applications, il vous suffit de déplacer l'emplacement du mot de passe en texte brut vers un autre fichier.

Si vous utilisez une forme de chiffrement pour éviter de stocker un mot de passe en texte brut, votre application devra tout de même le déchiffrer avec un autre mot de passe qu'elle aura déjà. Si un attaquant déploie beaucoup d'efforts pour accéder à votre système, vous pouvez être certain qu'il le saura également. Ce que vous faites est obscurcissant (et obtenant un faux sentiment de sécurité) plutôt que de le sécuriser réellement.

Une solution plus sécurisée consiste pour un utilisateur à fournir le mot de passe (ou un mot de passe pour déchiffrer le mot de passe de la base de données) lors du démarrage de votre application, mais cela rendra l'administration vraiment difficile. Et si vous êtes déjà paranoïaque (le bon type de sécurité, pas le fou) que quelqu'un ait accès à votre serveur, vous devez considérer que le mot de passe de la base de données résidera dans la mémoire système.

En dehors de cela, conservez votre mot de passe dans votre fichier de configuration (vous pouvez être presque sûr que le serveur ne sera pas visible par le monde extérieur), verrouillez votre système et accordez à l'utilisateur de la base de données uniquement les autorisations minimales requises.

27
jeconom

Une option consiste à utiliser Jasypt avec son intégration Spring afin de pouvoir stocker le nom d'utilisateur/mot de passe en tant que propriétés dans un fichier de propriétés standard mais sous une forme chiffrée. Jasypt se chargera du déchiffrement en toute transparence

6
geoand

Avoir des mots de passe en configuration est vraiment nul et il n’ya pas de solution miracle pour cela . Cependant, cette solution est compatible avec la plupart des systèmes de sécurité bla-bla-bla . De plus, elle masquera également les informations d’identité de votre MSC. 

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);
    }

}

Votre haricot:

<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>

Votre dossier de propriété:

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

Remarque: Si vous utilisez la stratégie JCE illimitée, vous pouvez également utiliser un meilleur algorithme de cryptage, mais comme nous ne faisons rien d’obscurcissement, cela fera l'affaire et ne vous laissera pas avec des sessions de débogage.

Mettre à jour:

Vous pouvez l'utiliser pour générer votre mot de passe:

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]));
        }
    }
}
5
Hannes

Vous pouvez le conserver sur le serveur d'applications et obtenir le nom jndi.

Par exemple, si vous utilisez une implémentation jpa telle que hibernate/Eclipse-link, vous pouvez la définir comme suit:

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>

Sur le serveur d'applications, vous devez définir la connexion à la base de données (source de données) dans le fichier de configuration du serveur. Dans Jboss 7, il s'agit de stadalone.xml jboss datasource .

4
bmlynarczyk

Bon et vieux problème de poulet et d'oeufs.

Est-ce une bonne idée de conserver le nom d'utilisateur et le mot de passe de la base de données dans unxml et importez-le dans le fichier de sécurité de la sécurité de printemps?

C'est une meilleure idée que de la stocker en clair dans le code source, mais pire que d'avoir un serveur d'applications d'entreprise qui la gère pour vous (comme SAP NetWeaver ou Oracle WebLogic).

La bonne partie est que vous séparez votre application des informations d'identification, ce qui permet une configuration spécifique à l'environnement et des restrictions de sécurité du système d'exploitation.

Comme la plupart des solutions logicielles, cela dépend. Et dans votre cas, cela dépend de combien d'effort est censé être consacré à cette fin.

Y a-t-il une meilleure option?

Même si vous stockez les informations d'identification dans un fichier, vous devez au minimum le coder ou, si possible, le chiffrer. Mais encore une fois, cela ne fera que "brouiller" le vrai mot de passe. 

Par exemple, pour chiffrer avec un algorithme synchrone, vous aurez besoin d'une clé secrète. Alors, où cette clé secrète sera-t-elle stockée? Il s’agit d’une sécurité circulaire qui renforce l’effort de piratage du mot de passe sans éliminer le risque.

Suggestion 1: Rendez le fichier qui stocke les informations d'identification uniquement accessible à l'utilisateur administrateur du système d'exploitation et à votre utilisateur système, afin qu'il puisse le lire. Utilisez le cryptage par clé secrète par dessus. Personnellement, je vais toujours avec l'algorithme AES 256 .

Suggestion 2: Au lieu de le stocker dans un fichier, demandez à l'équipe de l'infrastructure (administrateurs du super-système d'exploitation) de vous envoyer le mot de passe crypté en tant que paramètre système. Déléguez la responsabilité de la sécurité des justificatifs d'identité à l'équipe d'infrastructure. Il s'agit de l'approche actuelle pour intégration d'AWS Beanstalk avec RDS .

Si vous êtes fou de sécurité:

  • Si vous ne faites pas confiance à votre équipe d'infrastructure, vous voudrez peut-être que le mot de passe De l'application soit saisi manuellement par un humain au démarrage de l'application . Vous devrez également gérer les inconvénients, comme par exemple avoir toujours besoin d'une présence humaine pour le démarrage de l'application et d'une mise à l'échelle horizontale.

  • Vous voudrez peut-être que le mot de passe soit manipulé "physiquement" comme dans un support DVD .__ qui doit être inséré sur le serveur par un membre opérationnel De plus, vous devrez gérer l'accès sur le périphérique Au sein de votre système d'exploitation.

N'ayez pas peur d'en parler à vos parties prenantes aussi. Demandez-leur quel est le "assez" acceptable et soyez heureux à ce sujet.

Il y aura toujours un risque lors du stockage des informations d'identification.

Si j'ai besoin de chiffrer le mot de passe, comment le faire et comment trouver leversion cryptée du mot de passe sur phpMyAdmin? MySQL

Évitez de copier votre mot de passe. Vous devez gérer les informations d'identification à l'intérieur de votre serveur.

Pour une solution, nous avons créé un logiciel personnalisé accessible uniquement par les administrateurs via le protocole X11 ou la console, basé uniquement sur la API Java Crypt . Ce logiciel a été conçu pour modifier les informations d'identification de manière sécurisée.

Le mot de passe passe toujours par des connexions SSH sécurisées (si distantes) ou même locales, et uniquement entre les administrateurs et le serveur, car les autorisations ont été définies de cette manière dans le système d'exploitation.

Quant à PhpMyAdmin, il a sa propre manière de gérer les mots de passe, et vous ne pourrez probablement pas intégrer les deux solutions en une seule sans un effort de personnalisation important. Ne stockez pas les mots de passe de PhpMyAdmin ou de tout autre client MySQL, cela ne ferait qu'augmenter votre risque de sécurité.

3
BonanzaOne

vous pouvez garder dans le fichier de propriétés

Dans mon projet, j'ai créé un fichier database.properties sous META-INF dans STS IDE.

2
SpringLearner

Dans Rails, je conserve les données sensibles dans les variables d'environnement dans un fichier .env et les ajoute au fichier .gitignore. Je ne suis pas sûr que vous puissiez faire quelque chose de similaire. 

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

Vous pouvez créer un mot de passe crypté avec quelque chose comme ceci:

http://bcrypthashgenerator.apphb.com/

..et vous saurez quel est le mot de passe et vous pourrez ajouter la version cryptée à la table correcte via phpMyadmin.

Pourriez-vous simplement conserver les mots de passe dans votre référentiel local, sans les déployer sur la télécommande? Je me demande si vous pourriez configurer un scénario similaire à Rails ENV.

Avez-vous regardé quelque chose comme ceci: http://www.jasypt.org/spring3.html

1
Jordan

Comme quelqu'un d'autre l'a mentionné, si vous stockez des mots de passe sur le serveur, vous ne pouvez rien faire si l'attaquant obtient l'accès à votre ordinateur. La seule alternative viable consiste à utiliser une connexion SSL et une authentification basée sur un certificat.

La méthode ci-dessus a déjà été discutée sur SO et answer a été fourni .

0
mindas

Il est recommandé d'utiliser la configuration de la source de données dans votre serveur d'applications. Et essayez d'utiliser cela en utilisant la recherche JNDI en utilisant le contexte

0
saysiva