java 在spring xml文件中隐藏数据源密码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4196545/
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-10-30 05:16:07  来源:igfitidea点击:

Hide datasource password in spring xml file

javaxmlspringkeystorepassword-encryption

提问by blow

there is a way to hide/encrypt password in xml spring config file? I read that is possible with a "custom" subclass of DataSource, but the solutions keep key in same config file as plain text...so is a bit useless.

有没有办法在 xml spring 配置文件中隐藏/加密密码?我读到使用 DataSource 的“自定义”子类是可能的,但是解决方案将密钥保存在与纯文本相同的配置文件中......所以有点没用。

There is a way to use KeyStore for this? For example read the value from a keystore.

有没有办法为此使用 KeyStore?例如从密钥库中读取值。

Thanks all.

谢谢大家。

采纳答案by CoolBeans

Yes, you can do that. You will have to create a wrapper bean around the data source class. Here is an example of how I have done it before. Hope this helps!

是的,你可以这样做。您必须围绕数据源类创建一个包装 bean。这是我以前如何做到的一个例子。希望这可以帮助!

<beans>
    <bean id="someDao" class="com.dao.SomeDAOImpl">
         <property name="datasource">
            <ref local="secureDataSource"/>
        </property>
    </bean>
    <bean id="secureDataSource" class="com.ds.SecureDataSource">
        <property name="driverClassName">
            <value><your driver></value>
        </property>
        <property name="url">
            <value><your url></value>
        </property>  
        <property name="username">
            <value><your user id></value>
        </property>
        <property name="password">
            <value><encrypted_pwd></value>
        </property> 
    </bean> 
</beans>

Then inside the SecureDataSource class you will need to decrypt the password.

然后在 SecureDataSource 类中,您需要解密密码。

import java.sql.Connection;
import java.sql.SQLException;


public class SecureDataSource extends DriverManagerDataSource{

    private String url;
    private String username;
    private String password;
    /**
     * @param url the url to set
     */
    public void setUrl(String url) {
        this.url = url;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    protected Connection getConnectionFromDriverManager() throws SQLException {
        String decryptedPassword = null;
        //decrypt the password here
        return getConnectionFromDriverManager(url,username,decryptedPassword);
    }
}

回答by ordnungswidrig

What is the purpose of hiding the password? I suggest you configure the datasource in the container (Tomcat, JBoss or whatever you use) and inject the datasource into your application using jndi:

隐藏密码的目的是什么?我建议您在容器(Tomcat、JBoss 或任何您使用的)中配置数据源,并使用 jndi 将数据源注入您的应用程序:

<jee:jndi-lookup id="thedatasource"
                     jndi-name="java:comp/env/jdbc/thedatasource"
                     lookup-on-startup="false"
                     expected-type="javax.sql.DataSource"/>

This way you have not to expose and password in your application but only in the servlet container.

这样您就不必在应用程序中公开和密码,而只需在 servlet 容器中公开。

回答by Sean Patrick Floyd

Good options have been given, another obvious answer is to use the PropertyPlaceholderConfigurer:

已经给出了很好的选择,另一个明显的答案是使用PropertyPlaceholderConfigurer

<context:property-placeholder
    system-properties-mode="OVERRIDE" 
    location="classpath:database.properties" />

<bean id="dataSource" class="com.whatever.datasource.you.Use">
    <property name="password" value="${database.password}" />
</bean> 

Now you can keep your password either as a property in a properties file (which you might create during deployment if you don't want to have it in the SCM) or as a System Property (which will hopefully also be beyond reach of other developers).

现在,您可以将您的密码作为属性文件中的属性(如果您不想在 SCM 中使用它,您可以在部署期间创建)或作为系统属性(希望其他开发人员也无法访问) )。

Clarification:create during deploymentis somewhat vague. I guess you will have to write an installer that generates the properties file dynamically on the end user's machine, probably coupled with a sign up / log in mechanism.

澄清:在部署期间创建有点含糊。我猜您必须编写一个安装程序,在最终用户的机器上动态生成属性文件,可能还需要注册/登录机制。



EDIT:I still haven't figured out who you are hiding the information from. Two theories:

编辑:我仍然没有弄清楚你在向谁隐藏信息。两种理论:

a) People who have access to your source code
b) Your customers

a) 有权访问您的源代码的人
b) 您的客户

If it's a), then go my way. All other ways can easily be breached by the other developer just starting your application with a debugger (and suddenly he's inside the datasource object and sees the password).

如果是 a),那就走我的路。所有其他方式很容易被其他开发人员破坏,只需使用调试器启动您的应用程序(突然他在数据源对象中并看到密码)。

If it's b), then you have no chance, basically. The customer has tons of possibilities to get at your password: debuggers, agents, bytecode manipulation, loadtime weaving etc. Even if he doesn't do any of that, he will just have to attach a port sniffer to get at the password in clear text. The only safe thing to do is have a username / password per customer (never store a global password at your customer's machine).

如果是 b),那么基本上你就没有机会了。客户有很多可能获取你的密码:调试器、代理、字节码操作、加载时间编织等。即使他不做任何这些,他也只需要附加一个端口嗅探器来清楚地获取密码文本。唯一安全的做法是为每个客户设置一个用户名/密码(永远不要在客户的机器上存储全局密码)。

回答by Marc de Verdelhan

I had the same question recently. I wanted to store a hashed version of the password in a .properties file. I did the trick thanks to the previous options: I extended the DelegatingDataSourceand overrided the getConnection([...])methods.

我最近有同样的问题。我想将密码的散列版本存储在 .properties 文件中。由于之前的选项,我做到了:我扩展DelegatingDataSource并覆盖了getConnection([...])方法。

public class UnhashingDataSource extends DelegatingDataSource {

    private static final Logger LOGGER = Logger.getLogger(UnhashingDataSource.class);
    private static final int HEX_RADIX = 16;
    private static final String DB_PASS = "a_sample_password";

    @Override
    public Connection getConnection() throws SQLException {
        DriverManagerDataSource dataSource = (DriverManagerDataSource) getTargetDataSource();
        return getConnection(dataSource.getUsername(), dataSource.getPassword());
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        try {
            DataSource datasource = getTargetDataSource();
            if (datasource == null) {
                throw new RuntimeException("targetDataSource is null");
            }
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.reset();
            md.update(DB_PASS.getBytes());
            if (password.equals(getHexString(md.digest()))) {
                return datasource.getConnection(username, DB_PASS);
            } else {
                throw new RuntimeException("Unable to connect to DB");
            }
        } catch (NoSuchAlgorithmException e) {
            LOGGER.error("Unknown algorithm");
        }
        return null;
    }

    private String getHexString(final byte[] messageDigest) {
        BigInteger bigInt = new BigInteger(1, messageDigest);
        return bigInt.toString(HEX_RADIX);
    }
}

Then, here is how I used it in my applicationContext.xml:

然后,这是我如何在我的applicationContext.xml

# Using the unhashing datasource
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="unhashingDataSource" />
    # ...
</bean>
<bean id="hashedDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${datasource.driverClassName}" />
    <property name="url" value="${datasource.url}" />
    <property name="username" value="${datasource.username}" />
    <property name="password" value="${datasource.hash}" />
</bean>
<bean id="unhashingDataSource"
    class="my.package.UnhashingDataSource">
    <property name="targetDataSource" ref="hashedDataSource" />
</bean>

Where datasource.hashis a property (from a .properties file) stored like:

datasource.hash属性(来自 .properties 文件)存储在哪里,如:

datasource.hash = 2e54b0667ef542e3398c55a08a4e04e69b9769e8

The plain password is still in bytecode but not directly in a .properties file anymore.

普通密码仍然在字节码中,但不再直接在 .properties 文件中。

回答by Bimales Mandal

Thanks for all your post and queries.

感谢您的所有帖子和查询。

Hope for visitors its clear the technical way to encrypt password by reading this page. One important thing I would like to add here, if you are dealing with production then definitely will suggest you to use any "Secure Hash Algorithm" like SHA-256 with salt. You can consider secure hash algorithm using salt as industry standard.

希望访问者通过阅读此页面了解加密密码的技术方法。我想在这里添加一件重要的事情,如果您正在处理生产,那么肯定会建议您使用任何“安全散列算法”,例如带盐的 SHA-256。您可以考虑使用盐作为行业标准的安全哈希算法。