Druid连接池实现数据库加密

前言

不难发现,以我们现在的开发习惯,无论是公司的项目还是个人的项目,都会选择将源码上传到 Git 服务器(GitHub、Gitee 或是自建服务器),但只要将源码提交到公网服务器就会存在源码泄漏的风险,而数据库配置信息作为源码的一部分,一旦出现源码泄漏,那么数据库中的所有数据都会公之于众,其产生的不良后果无法预期。

于是为了避免这种问题的产生,我们至少要对数据库的密码进行加密操作,这样即使得到了源码,也不会造成数据的泄露。

怎么实现加密?

对于 Java 项目来说,要想快速实现数据库的加密,最简单可行的方案就是使用阿里巴巴提供的 Druid 来实现加密

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开源地址

扫描二维码关注公众号,回复: 14634860 查看本文章
Druid的功能点
  1. Druid 可以监控数据库访问性能,Druid 内置提供了一个功能强大的 StatFilter 插件,能够详细统计 SQL 的执行性能,这对于线上分析数据库访问性能有帮助。

  1. 替换数据库连接池 DBCP 和 C3P0,Druid 提供了一个高效、功能强大、可扩展性好的数据库连接池。

  1. 数据库密码加密,直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver 和 DruidDataSource 都支持 PasswordCallback。

  1. SQL 执行日志,Druid 提供了不同的 LogFilter,能够支持 Common-Logging、Log4j 和 JdkLog,你可以按需要选择相应的 LogFilter,监控你应用的数据库访问情况。

  1. 扩展 JDBC,如果我们要对 JDBC 层有编程的需求,可以通过 Druid 提供的 Filter-Chain 机制,很方便编写 JDBC 层的扩展插件。

在这里我们仅需要通过它来对配置文件中的数据库密码进行加密。

加密执行流程

在没有进行密码加密之前,项目的交互流程:

在使用了密码加密之后,项目的交互流程:

Druid实现数据库加密过程

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个部分的内容:

  1. privateKey:私钥,暂时不会用到,用于密码的加密;

  1. publicKey:公钥,用于密码的解密;

  1. 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包启动配置相对直接运行会麻烦一点,但是安全性得到了基本保证,还是可以滴~

猜你喜欢

转载自blog.csdn.net/qq_42263280/article/details/128883155