web-dev-qa-db-ja.com

データベースの資格情報はどこに保存すればよいですか?

データベースのユーザー名とパスワードをxmlファイルに保存して、春のセキュリティのセキュリティファイルにインポートするのは良い考えですか?より良いオプションはありますか?パスワードを暗号化する必要がある場合、その方法と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'/> 
      ....

注意:ユーザー関連のすべてのパスワードはすでに暗号化されているため、表の列ではなくデータベース自体のパスワードのみを非表示にすることを意図しています。このパスワードは、データベースに接続するためにアプリケーションで使用されます

21
Jack

何よりもまず、攻撃者がサーバーファイルにアクセスすると、パスワードを盗むことができることに注意してください。

アプリサーバーのデータソースを使用する場合は、プレーンテキストパスワードの場所を別のファイルに移動するだけです。

何らかの形式の暗号化を使用してプレーンテキストのパスワードの保存を回避する場合、アプリは既に持っている別のパスワードで暗号化を解除する必要があります。攻撃者がシステムにアクセスするためにかなりの時間を費やした場合、あなたも彼がそれを知っていると確信することができます。あなたがしているのは、実際にセキュリティを保護するのではなく、難読化することです(そして、セキュリティの誤った感覚を得ることです)。

より安全なソリューションは、ユーザーがアプリの起動時にパスワード(またはDBパスワードを解読するためのパスワード)を提供することですが、それは管理を本当に難しくします。そして、誰かがあなたのサーバーにアクセスしているという既に妄想的(良い種類ではなく、良い種類のセキュリティ)である場合、DBパスワードはシステムメモリに存在することを考慮する必要があります。

それ以外は、パスワードを構成ファイルに保存し(サーバーが外部に表示されないことをかなり確信で​​きます)、システムをロックダウンし、データベースユーザーに必要な最小限の権限のみを与えます。

30
jeconom

1つのオプションは、 Jasypt とSpring統合を使用して、usename/passwordをプロパティとして通常のプロパティファイルに暗号化された形式で保存できるようにすることです。 Jasyptは透過的に復号化を処理します

6
geoand

構成にパスワードを設定するのは非常に面倒で、特効薬はありません。ただし、このソリューションはほとんどのセキュリティbla-bla-blaに準拠しています。また、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);
    }

}

あなたの豆:

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

あなたのプロパティファイル:

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

注:無制限のJCEポリシーを使用する場合は、より優れた暗号化アルゴリズムを使用することもできますが、難読化のみを行うため、これはトリックを実行し、セッションをデバッグすることはできません。

更新:

これを使用してパスワードを生成できます。

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

アプリケーションサーバーで保持し、jndi名で取得できます。

たとえば、hibernate/Eclipse-linkなどのjpa実装を使用する場合、次のように定義できます。

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>

アプリケーションサーバーでは、サーバー設定ファイルでデータベース(データソース)への接続を定義する必要があります。 Jboss 7の場合、stadalone.xml jboss datasource です。

4
bmlynarczyk

古き良き鶏と卵の問題。

データベースのユーザー名とパスワードをxmlファイルに保存し、セキュリティファイルにインポートすることをお勧めします春のセキュリティの?

ソースコードにそのまま保存するよりも良いアイデアですが、ya(SAP NetWeaverやOracle WebLogicなど)向けにそれを処理するエンタープライズアプリケーションサーバーを持つよりも悪い考えです。

良い点は、資格情報からアプリケーションを分離し、環境固有の構成とOSセキュリティ制限を許可することです。

ほとんどのソフトウェアソリューションのように、それは依存します。そして、あなたの場合、それはその目的のためにどれだけの「努力」が捧げられることになっているかに依存します。

より良いオプションはありますか?

資格情報をファイルに保存している場合でも、少なくともエンコードするか、可能であれば暗号化する必要があります。しかし、これも実際のパスワードを「難読化」するだけです。

たとえば、同期アルゴリズムで暗号化するには、秘密鍵が必要になります。それで、この秘密鍵はどこに保存されますか?これは循環セキュリティであり、パスワードをハッキングする努力を強化しますが、リスクを排除しません。

提案1:資格情報を保存するファイルに、OS管理者ユーザーとシステムユーザーのみがアクセスできるようにします。その上で秘密鍵暗号化を使用します。個人的には、私は常に AES 256 アルゴリズムを使用しています。

推奨事項2:ファイルに保存する代わりに、インフラストラクチャチーム(スーパーOS管理者)に、システムパラメータとして暗号化されたパスワードを送信するように依頼します。資格情報セキュリティの責任をインフラストラクチャチームに委任します。これは、 AWS BeanstalkとRDSの統合 の現在のアプローチです。

セキュリティに夢中の場合:

  • インフラストラクチャチームを信頼していない場合は、アプリケーションの起動時に人間が手動でアプリケーションのパスワードを入力したい場合があります。アプリケーションの開始のために常に人間の存在が必要であり、水平スケーリングも必要であるように、その短所も処理する必要があります。

  • 運用メンバーがサーバーに挿入する必要があるDVDメディア内のように、パスワードを「物理的に」処理したい場合があります。同様に、OS内のデバイスへのアクセスを処理する必要があります。

それについてもあなたの利害関係者と話すことを恐れないでください。彼/彼らに「十分な」容認できるものを尋ね、それについて満足している。

資格情報を保存するときは常にリスクがあります。

パスワードを暗号化する必要がある場合、それを行う方法と、暗号化されたバージョンのパスワードをphpMyAdminで見つける方法は? MySQL

パスワードをコピーしないでください。サーバー内で資格情報を処理する必要があります。

1つのソリューションとして、X11プロトコルまたはコンソールを介して Java Crypt API のみに基づいて、管理者のみがアクセスできるカスタムソフトウェアを作成しました。このソフトウェアは、安全な方法で資格情報を変更するために設計されました。

パスワードは、安全なSSH接続(リモートの場合)またはローカルアクセスでも常に通過し、OSで許可がそのように定義されているため、管理者とサーバー間でのみ通過します。

PhpMyAdminについては、パスワードを処理する独自の方法があり、多くの場合、幅広いカスタマイズ作業なしでは両方のソリューションを1つに統合することはできません。 PhpMyAdminまたは他のMySQLクライアントのパスワードを保存しないでください。セキュリティリスクが高まるだけです。

3
Evandro Pomatti

プロパティファイルに保存できます

私のプロジェクトでは、STS IDEのMETA-INFの下にdatabase.propertiesを作成しました

1
SpringLearner

Railsでは、機密データを.envファイルの環境変数に保持し、ファイルを.gitignoreに追加します。同様のことができるかどうかはわかりません。

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

次のような方法で暗号化されたパスワードを作成できます。

http://bcrypthashgenerator.apphb.com/

..そして、パスワードが何であるかがわかり、phpMyadminを使用して暗号化されたバージョンを正しいテーブルに追加できます。

ローカルリポジトリにパスワードを保持するだけで、リモートに展開しないでください。 Rails ENV?と同様のシナリオをセットアップできるかどうか疑問に思っています。

次のようなものを見ましたか? http://www.jasypt.org/spring3.html

1
Jordan

他の人が言ったように、サーバーにパスワードを保存している場合、攻撃者がマシンにアクセスした場合にできることは何もありません。唯一の実行可能な代替手段は、SSL接続と証明書ベースの認証を使用することです。

上記の方法には、 既に説明済み on SOおよび 回答が提供されています があります。

0
mindas

App Serverでデータソース構成を使用することをお勧めします。そして、コンテキストを使用したJNDIルックアップを使用してそれを使用してみてください

0
saysiva