Java 我应该在哪里保存我的数据库的凭据?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23693796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 00:44:59  来源:igfitidea点击:

Where should I keep the credentials of my database?

javamysqltomcatspring-security

提问by Hyman

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

将数据库的用户名和密码保存在 xml 文件中并将其导入 spring security 的安全文件是否一个好主意?有没有更好的选择?如果我需要加密密码怎么做以及如何在 phpMyAdmin 上找到密码的加密版本?MySQL

login-service.xml

登录服务.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="Hyman" />
    <property name="password" value="alex123432" />
   </bean>

</beans>

myproject-security.xml

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.

请注意:由于所有与用户相关的密码都已加密,因此我只想隐藏 DATABASE 本身的密码,而不是表列。我的应用程序将使用此密码连接到数据库。

回答by SpringLearner

you can keep in properties file

您可以保留在属性文件中

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

在我的项目中,我在 STS IDE 的 META-INF 下创建了一个 database.properties

回答by bmlynarczyk

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

您可以将其保存在应用程序服务器上并通过 jndi 名称获取。

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

例如,如果您使用任何 jpa 实现,如 hibernate/eclipse-link,您可以将其定义如下

spring-security.xml

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.

在应用程序服务器上,您必须在服务器配置文件中定义与数据库(数据源)的连接。在 Jboss 7 的情况下,它是 stadalone.xml jboss 数据源

回答by geoand

One option is to use Jasyptwith 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

一种选择是将Jasypt与 Spring 集成一起使用,以便能够将用户名/密码作为属性存储在常规属性文件中,但以加密形式存储。Jasypt 将透明地处理解密

回答by jeconom

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.

一个更安全的解决方案是让用户在您的应用程序启动期间提供密码(或用于解密 DB 密码的密码),但这会使管理变得非常困难。如果您已经怀疑有人可以访问您的服务器(良好的安全性,而不是疯狂的那种),您应该考虑数据库密码将驻留在系统内存中。

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.

除此之外,将您的密码保存在您的配置文件中(您可以相当确信服务器不会向外界显示该文件),锁定您的系统并只为数据库用户提供所需的最低权限。

回答by mindas

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.

正如其他人提到的,如果您将密码存储在服务器上,那么如果攻击者获得对您机器的访问权,您将无能为力。唯一可行的替代方法是使用 SSL 连接和基于证书的身份验证。

The above method has already been discussedon SO and answer has been provided.

上述方法已经在 SO上讨论过,并且已经提供了答案

回答by Hannes

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.

在配置中设置密码真的很糟糕,而且没有灵丹妙药。但是,此解决方案符合大多数安全性 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);
    }

}

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.

注意:如果您使用无限制的 JCE 策略,您还可以使用更好的加密算法,但由于我们所做的只是混淆,这将起到作用,并且不会让您以调试会话结束。

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

回答by saysiva

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

建议在您的应用服务器中使用数据源配置。并尝试使用使用上下文的 JNDI 查找来使用它

回答by Jordan

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.

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

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

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.

..然后你就会知道密码是什么,你可以通过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?

您可以将密码保存在本地存储库中,而不将它们部署到远程吗?我想知道您是否可以设置与 Rails ENV 类似的场景?

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

你看过这样的东西:http: //www.jasypt.org/spring3.html

回答by Evandro Pomatti

Good and old chicken and egg problem.

好老鸡和鸡蛋的问题。

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

将数据库的用户名和密码保存在xml 文件中并将其导入 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).

这比将其简单地存储在源代码中更好,但比让企业应用服务器为您处理(如 SAP NetWeaver 或 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 256algorithm.

建议 1:使存储凭据的文件只能由操作系统管理员用户和您的系统用户访问,以便它可以读取它。在其上使用密钥加密。我个人总是使用AES 256算法。

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.

建议 2:不要将其存储在文件中,而是要求基础架构团队(超级操作系统管理员)将加密密码作为系统参数发送给您。将凭证安全的责任委托给基础架构团队。这是AWS Beanstalk 与 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.

  • 如果您不信任您的基础架构团队,您可能希望在应用程序启动时由人工手动输入应用程序的密码。您还需要处理它的缺点,比如在应用程序启动时总是需要有人在场,以及水平扩展。

  • 您可能希望像在 DVD 媒体中那样“物理地”处理密码,该媒体必须由操作成员插入服务器。您还必须在您的操作系统中处理对设备的访问。

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 theencrypted version of password on phpMyAdmin? MySQL

如果我需要加密密码怎么做以及如何在 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.

对于一个解决方案,我们制作了一个只能由管理员通过 X11 协议或控制台访问的自定义软件,仅基于Java Crypt API。该软件旨在以安全的方式更改凭据。

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.

密码总是在安全的 SSH 连接(如果远程)或什至本地访问中传输,并且仅在管理员和服务器之间传输,因为权限是在操作系统中以这种方式定义的。

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.

至于 PhpMyAdmin,它有自己的处理密码的方式,如果没有广泛的定制工作,您很可能无法将这两种解决方案集成到一个中。不要为 PhpMyAdmin 或任何其他 MySQL 客户端存储密码,这只会增加您的安全风险。