赞
踩
不难发现,以我们现在的开发习惯,无论是公司的项目还是个人的项目,都会选择将源码上传到 Git 服务器(GitHub、Gitee 或是自建服务器),但只要将源码提交到公网服务器就会存在源码泄漏的风险,而数据库配置信息作为源码的一部分,一旦出现源码泄漏,那么数据库中的所有数据都会公之于众,其产生的不良后果无法预期。
于是为了避免这种问题的产生,我们至少要对数据库的密码进行加密操作,这样即使得到了源码,也不会造成数据的泄露。
怎么实现加密?
对于 Java 项目来说,要想快速实现数据库的加密,最简单可行的方案就是使用阿里巴巴提供的 Druid 来实现加密。
Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成,该项目主要是为了扩展 JDBC 的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计 SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。
Druid 是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括 DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。除此以外,Druid 提供了强大的监控和扩展功能,当然也包含了数据库的加密功能。
Druid 已经在阿里巴巴部署了超过 600 个应用,经过了很多生产环境大规模部署的严苛考验。
同时 Druid 不仅仅是一个数据库连接池,它包括四个部分:
Druid 是一个 JDBC 组件,它包括三个部分:
基于 Filter-Chain 模式的插件体系。
DruidDataSource 高效可管理的数据库连接池。
SQLParser
Druid的功能点
Druid 可以监控数据库访问性能,Druid 内置提供了一个功能强大的 StatFilter 插件,能够详细统计 SQL 的执行性能,这对于线上分析数据库访问性能有帮助。
替换数据库连接池 DBCP 和 C3P0,Druid 提供了一个高效、功能强大、可扩展性好的数据库连接池。
数据库密码加密,直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver 和 DruidDataSource 都支持 PasswordCallback。
SQL 执行日志,Druid 提供了不同的 LogFilter,能够支持 Common-Logging、Log4j 和 JdkLog,你可以按需要选择相应的 LogFilter,监控你应用的数据库访问情况。
扩展 JDBC,如果我们要对 JDBC 层有编程的需求,可以通过 Druid 提供的 Filter-Chain 机制,很方便编写 JDBC 层的扩展插件。
在这里我们仅需要通过它来对配置文件中的数据库密码进行加密。
在没有进行密码加密之前,项目的交互流程:
在使用了密码加密之后,项目的交互流程:
1,添加Druid依赖
这里以SpringBoot项目为例,引入SpringBoot的集成依赖:
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.2.14</version>
- </dependency>
2,调用工具类生成密文
借助Druid中的ConfigTools工具类来加密数据库对应的密码:
- @Test
- void method2() throws Exception {
- //定义数据库密码,以123456为例
- String password = "123456";
- //调用druid的工具类来加密密码
- ConfigTools.main(new String[]{password});
- }
执行后即可得到如下结果:
privateKey:MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAv5WmBXjC7ysGEz5455YGNiqf52HFTmF/+4efK1bxrXPGNt3idKYXapO3RktjATl2KQhVQo9v9JR98sC8ROrHCQIDAQABAkAtZh7jaQx4dG+KG+G2rzxllZAy2l5RBpW3WxoCwSWf/kfIyNjaNTEQXZAF9a+9JSaII3c8x6+K3vQccVyzoB8BAiEA9nVYs4lJqa4kczuG8J9jgy9LX9UK2vuZKUzMJ/BQ9zkCIQDHAHJU0NIa5McWWwziKhq6BI1Dfje6Jt2cIkFPpBL+UQIhAIkBkt27ZAe/luO4I7t/34H9uJj9hZtWYj5jQtqw7VGBAiEAtTnn5OvC23ELCYXjpreXXV4104hHccRhPwZHGiMelPECIQDp0g+5HMxLTI3EWuHlAOOZfiwCZy0S+uexT2xXGUL/wg==
publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ==
password:daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==
可以看到执行结果包含3个部分的内容:
privateKey:私钥,暂时不会用到,用于密码的加密;
publicKey:公钥,用于密码的解密;
password:密文,加密之后的密码。
这里我们主要通过publicKey和password来实现对数据库的加密,将明文密码转换为密文。
3,添加到yml配置文件
得到执行结果后,我们需要将公钥和密文分别添加到项目的yml配置文件中
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: url: jdbc:mysql://localhost:3306/store_user?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root #生成后的密文 password: daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA== filters: config connect-properties: config.decrypt: true #生成的公钥 config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ== mybatis-plus: mapper-locations: classpath*:mapper/*.xml configuration: map-underscore-to-camel-case: true auto-mapping-behavior: full lazy-loading-enabled: true aggressive-lazy-loading: false type-aliases-package: com.yy.pojo #设置别名
注意:但是这样并不完全安全,当我们将密文和公钥都写入配置文件,这就会造成当有人拿到密文和公钥之后,就可以使用 Druid 将加密的密码还原出来了,这就好比一把插着钥匙的锁是极不安全的。
因此我们正确的使用方式是:将公钥找一个安全的地方保存起来,每次在项目启动时动态的将公钥设置到项目中,这样就可以有效的保证密码的安全了。,
4,优化yml配置文件
接下来我们将 Spring Boot 的公钥设置为配置项,在项目运行时再替换为具体的值,最终的安全配置信息如下:
- spring:
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- type: com.alibaba.druid.pool.DruidDataSource
- druid:
- url: jdbc:mysql://localhost:3306/store_user?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
- username: root
- #生成后的密文
- password: daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==
- filters: config
- connect-properties:
- config.decrypt: true
- #生成的公钥
- config.decrypt.key: ${spring.datasource.druid.publicKey}
这里为了保证安全,我们可以将公钥被修改成“${spring.datasource.druid.publickey}”,这就相当于使用占位符去替代公钥,等项目启动时再更换上具体的值去执行。
注意:“spring.datasource.druid.publickey”并非是固定不可变的 key,此 key 值用户可自行定义。
开发环境中只需要在 Idea 的启动参数中配置公钥的值即可,如下图所示:
当我们输入正确的公钥值时程序可以正常运行,当输入一个错误的公钥值时就会提示解码失败,如下图所示:
生产环境下启动时,我们可以动态的设置公钥的值即可。如下:
java -jar xxx.jar --spring.datasource.druid.publickey=公钥值
最后测试数据库操作,可以对数据库数据进行正常访问,加密操作成功。
这样,我们就完成 MySQL 密码的加密了,当 Spring Boot 项目启动时,Druid 的拦截器会使用密文和公钥将密码还原成真实的密码以供项目使用,当然这一切都无需人工干预(无需编写任何代码),Druid 已经帮我们封装好了,我们只需要通过以上配置即可。
这里补充一句:上面提到了,我们不建议直接将公钥值填在yml文件中,因为会造成密码泄露的风险是有理可循的。这里我们通过Druid工具类做个还原操作即可证实这一点:
- @Test
- void method3() throws Exception {
- String publicKey="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+VpgV4wu8rBhM+eOeWBjYqn+dhxU5hf/uHnytW8a1zxjbd4nSmF2qTt0ZLYwE5dikIVUKPb/SUffLAvETqxwkCAwEAAQ==";
- String pwd="daOJOrMQgK7yxCkUW7FRhSmdDFZIqgMmmXfRw5FM/zsNM08Tgdu+I9I/bJ3akSf4w/fV0IjY/qjDE3jBw20tAA==";
- System.out.println(ConfigTools.decrypt(publicKey, pwd));
- }
这样就得到破译后的原密码了,这是很危险的。
所以,当公钥,密文全部显示配置后,密码源是能够被获取的,那么我们数据库加密就没有什么意义了。虽然通过配置启动参数或jar包启动配置相对直接运行会麻烦一点,但是安全性得到了基本保证,还是可以滴~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。