简体   繁体   English

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

[英]Hide datasource password in spring xml file

there is a way to hide/encrypt password in xml spring config file? 有一种方法可以在xml spring配置文件中隐藏/加密密码吗? 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. 我读过可以使用DataSource的“自定义”子类,但解决方案将密钥保存在与纯文本相同的配置文件中......所以有点无用。

There is a way to use KeyStore for this? 有一种方法可以使用KeyStore吗? For example read the value from a keystore. 例如,从密钥库中读取值。

Thanks all. 谢谢大家。

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容器中公开密码。

Yes, you can do that. 是的,你可以这么做。 You will have to create a wrapper bean around the data source class. 您必须在数据源类周围创建一个包装器bean。 Here is an example of how I have done it before. 这是我以前如何做到的一个例子。 Hope this helps! 希望这可以帮助!

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

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 deployment is 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 a)有权访问您的源代码的人
b) Your customers b)您的客户

If it's a), then go my way. 如果是a),那就走吧。 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). 使用调试器启动应用程序的其他开发人员很容易违反所有其他方法(突然他在数据源对象内部并看到密码)。

If it's b), then you have no chance, basically. 如果是b),那么基本上你没有机会。 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). 唯一安全的做法是为每个客户提供一个用户名/密码(永远不要在客户的机器上存储全局密码)。

I had the same question recently. 我最近有同样的问题。 I wanted to store a hashed version of the password in a .properties file. 我想在.properties文件中存储密码的哈希版本。 I did the trick thanks to the previous options: I extended the DelegatingDataSource and overrided the getConnection([...]) methods. 由于以前的选项,我做了这个技巧:我扩展了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.hash is 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文件中。

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. 我想在这里添加一件重要的事情,如果您正在处理生产,那么肯定会建议您使用任何“安全哈希算法”,如SHA-256和盐。 You can consider secure hash algorithm using salt as industry standard. 您可以考虑使用salt作为行业标准的安全哈希算法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在属性文件中设置 - 通过 Spring 启动 Bcrypt 数据源密码 - Set In Property File - Bcrypt datasource password over Spring Boot 如何在spring.xml配置文件中连接SqlMapClientFactoryBean的数据源 - How to wire SqlMapClientFactoryBean a dataSource in spring.xml config file 如何在xml配置文件中获取spring声明的数据源 - how to get a spring declared datasource in an xml config file 将数据源密码放在context.xml之外 - Place datasource password outside context.xml Spring 单独属性文件中的数据源密码导致“无法确定合适的驱动程序类” - Spring DataSource password in separate properties file causes “Failed to determine a suitable driver class” 隐藏文本文件中的密码 - Hide password in text file Swagger - spring 狐狸 - 隐藏密码 - Swagger - spring fox - hide password Spring 数据 JPA - 不要在 XML 文件中硬编码密码 - Spring data JPA - Do not hard code password in XML file XML文件中的Springboot多数据源 - Springboot multi datasource in xml file Heroku 是否重写了 Spring Boot 的 spring.datasource.url、spring.datasource.username 和 spring.datasource.password 属性? - Is Heroku rewrites Spring Boot's spring.datasource.url, spring.datasource.username and spring.datasource.password properties?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM