IT培訓-高端面授IT培訓機構
          云和教育:云和數據集團高端IT職業教育品牌
          • 國家級
            全民數字素養與技能培訓基地
          • 河南省
            第一批產教融合型企業建設培育單位
          • 鄭州市
            數字技能人才(碼農)培養評價聯盟
          當前位置:
          首頁IT問答正文

          Java培訓:什么是sMybatisPlus數據安全?

          • 發布時間:
            2022-12-01
          • 版權所有:
            云和教育
          • 分享:

          存在數據庫中的數據對于普通用戶而言是不可見的,好像是藏起來了一樣,但對于開發者,只要知道數據庫的連接地址、用戶名、密碼,則數據不再安全;這也意味著,一旦連接數據庫的配置文件暴露出去,則數據不再安全。

          應用場景

          開發中的數據庫配置文件或配置中心中的配置信息

          API介紹

          MybatisPlus中有個針對配置項加密處理的

           

          1669012039360_1.jpg

          1669011956303_2.jpg

          代碼實現

          1.創建mp工程

          創建maven工程,結構如下:

          1669012124855_3.jpg

          2.代碼編寫

          pom.xml

              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>com.baomidou</groupId>
                      <artifactId>mybatis-plus-boot-starter</artifactId>
                      <version>3.4.1</version>
                  </dependency>
                  <dependency>
                      <groupId>mysql</groupId>
                      <artifactId>mysql-connector-java</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>org.projectlombok</groupId>
                      <artifactId>lombok</artifactId>
                      <scope>provided</scope>
                  </dependency>
              </dependencies>

          application.yml

          spring:
            datasource:
              url: jdbc:mysql://localhost:3306/springboot?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
              driver-class-name: com.mysql.cj.jdbc.Driver
              username: root
              password: root
          mybatis-plus:
            type-aliases-package: com.itheima.pojo

          啟動類

          package com.itheima;
          
          import org.mybatis.spring.annotation.MapperScan;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.autoconfigure.SpringBootApplication;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima
           */
          @SpringBootApplication
          @MapperScan(basePackages = "com.itheima.mapper")
          public class App {
              public static void main(String[] args) {
                  SpringApplication.run(App.class,args);
              }
          }

          pojo

          package com.itheima.pojo;
          
          import com.baomidou.mybatisplus.annotation.TableField;
          import lombok.Data;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima.pojo
           */
          @Data
          public class User {
              private Integer id;
              private String username;
              @TableField(select = false)
              private String password;
              private String salt;
          
          }

          mapper

          package com.itheima.mapper;
          
          import com.baomidou.mybatisplus.core.mapper.BaseMapper;
          import com.itheima.pojo.User;
          import org.springframework.stereotype.Repository;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima.mapper
           */
          @Repository
          public interface UserMapper extends BaseMapper<User> {
          }

          service接口與實現類

          package com.itheima.service;
          
          import com.baomidou.mybatisplus.extension.service.IService;
          import com.itheima.pojo.User;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima.service
           */
          public interface UserService extends IService<User> {
          }
          package com.itheima.service.impl;
          
          import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
          import com.itheima.mapper.UserMapper;
          import com.itheima.pojo.User;
          import com.itheima.service.UserService;
          import org.springframework.stereotype.Service;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima.service.impl
           */
          @Service
          public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
          }

          controller

          package com.itheima.controller;
          
          import com.itheima.pojo.User;
          import com.itheima.service.UserService;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.web.bind.annotation.GetMapping;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;
          
          import java.util.List;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima.controller
           */
          @RestController
          @RequestMapping("user")
          public class UserController {
          
              @Autowired
              private UserService userService;
          
              @GetMapping
              public List<User> listAll(){
                  return userService.list();
              }
          
          }

          啟動測試

          生成加密后的內容

          package com.itheima;
          
          import com.baomidou.mybatisplus.core.toolkit.AES;
          import org.mybatis.spring.annotation.MapperScan;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.autoconfigure.SpringBootApplication;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima
           */
          @SpringBootApplication
          @MapperScan(basePackages = "com.itheima.mapper")
          public class App {
              public static void main(String[] args) {
                  String secretKey = AES.generateRandomKey();
                  System.out.println("secretKey:" + secretKey);
          
                  String url = AES.encrypt("jdbc:mysql://localhost:3306/springboot?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai", secretKey);
                  String username = AES.encrypt("username", secretKey);
                  String password = AES.encrypt("password", secretKey);
                  System.out.println("url=" +url );
                  System.out.println("username=" +username );
                  System.out.println("password=" +password );
          
                  SpringApplication.run(App.class,args);
              }
          }

          1669012363492_4.jpg

          替換配置文件

          spring:
            datasource:
              url: mpw:wT9PqZ9Hf4VWgXDuZ/Z1JKfdDyS0sSu3+O2qDkJ/Ulnabpq3z1lZbiThWseQ4DQSx3+SWpufsTysjdYhn6Scsa77AzIIaUgv8DZ17gPxAq88AISmxd9OjxidmY50uBVMkGhP9qAted45zuHBzVrw6Q==
              driver-class-name: com.mysql.cj.jdbc.Driver
              username: mpw:Pnh++mI45YrC4s6JveJYaA==
              password: mpw:Pnh++mI45YrC4s6JveJYaA==
          mybatis-plus:
            type-aliases-package: com.itheima.pojo

          添加啟動參數

          1669012409610_5.jpg

          運行效果

          1669012455176_6.jpg

          3.優化

          目的

          啟動時,需要指定密鑰才能使用,如果我們把它封裝到一個jar里,讓它啟動時自動去加載密鑰,且密鑰可配置,那這樣就更靈活了。

          分析

          通過查看MybatisPlus加載的源碼,其做解密處理的類如下:

          /*
           * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
           * <p>
           * Licensed under the Apache License, Version 2.0 (the "License"); you may not
           * use this file except in compliance with the License. You may obtain a copy of
           * the License at
           * <p>
           * https://www.apache.org/licenses/LICENSE-2.0
           * <p>
           * Unless required by applicable law or agreed to in writing, software
           * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
           * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
           * License for the specific language governing permissions and limitations under
           * the License.
           */
          package com.baomidou.mybatisplus.autoconfigure;
          
          import com.baomidou.mybatisplus.core.toolkit.AES;
          import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
          import com.baomidou.mybatisplus.core.toolkit.StringUtils;
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.env.EnvironmentPostProcessor;
          import org.springframework.boot.env.OriginTrackedMapPropertySource;
          import org.springframework.core.env.ConfigurableEnvironment;
          import org.springframework.core.env.MapPropertySource;
          import org.springframework.core.env.PropertySource;
          import org.springframework.core.env.SimpleCommandLinePropertySource;
          
          import java.util.HashMap;
          
          /**
           * 安全加密處理器
           *
           * @author hubin
           * @since 2020-05-23
           */
          public class SafetyEncryptProcessor implements EnvironmentPostProcessor {
          
              @Override
              public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
                  /**
                   * 命令行中獲取密鑰
                   */
                  String mpwKey = null;
                  for (PropertySource<?> ps : environment.getPropertySources()) {
                      if (ps instanceof SimpleCommandLinePropertySource) {
                          SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps;
                          mpwKey = source.getProperty("mpw.key");
                          break;
                      }
                  }
                  /**
                   * 處理加密內容
                   */
                  if (StringUtils.isNotBlank(mpwKey)) {
                      HashMap<String, Object> map = new HashMap<>();
                      for (PropertySource<?> ps : environment.getPropertySources()) {
                          if (ps instanceof OriginTrackedMapPropertySource) {
                              OriginTrackedMapPropertySource source = (OriginTrackedMapPropertySource) ps;
                              for (String name : source.getPropertyNames()) {
                                  Object value = source.getProperty(name);
                                  if (value instanceof String) {
                                      String str = (String) value;
                                      if (str.startsWith("mpw:")) {
                                          map.put(name, AES.decrypt(str.substring(4), mpwKey));
                                      }
                                  }
                              }
                          }
                      }
                      // 將解密的數據放入環境變量,并處于第一優先級上
                      if (CollectionUtils.isNotEmpty(map)) {
                          environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map));
                      }
                  }
              }
          }

          其使用了SPI原理,在類所在的jar下的META-INF/spring.factories中配置了這個SafetyEncryptProcessor。那我們能否也來定義一個這樣的配置處理器,判斷環境配置中是否配置了–mpw.key,如果沒有配置,則給它配置上,這樣就不用在啟動時添加參數來運行了。

          1669012544198_7.jpg

          實現

          創建配置工程mysafe

          1669012588892_8.jpg

          代碼清單

          pom.xml

          <parent>
              <artifactId>spring-boot-starter-parent</artifactId>
              <groupId>org.springframework.boot</groupId>
              <version>2.3.8.RELEASE</version>
          </parent>
          <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter</artifactId>
              </dependency>
          </dependencies>

          SafetyEncryptProcessor

          package com.itheima;
          
          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.env.EnvironmentPostProcessor;
          import org.springframework.core.Ordered;
          import org.springframework.core.env.ConfigurableEnvironment;
          import org.springframework.core.env.PropertySource;
          import org.springframework.core.env.SimpleCommandLinePropertySource;
          import org.springframework.core.io.ClassPathResource;
          import org.springframework.util.StringUtils;
          
          import java.io.IOException;
          import java.util.Properties;
          
          /**
           * @version 1.0
           * @description 說明
           * @package com.itheima
           */
          public class SafetyEncryptProcessor implements EnvironmentPostProcessor, Ordered {
          
              @Override
              public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
                  Properties pro = new Properties();
                  try {
                      pro.load(new ClassPathResource("ert.properties").getInputStream());
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
                  /**
                   * 命令行中獲取密鑰
                   */
                  String mpwKey = null;
                  for (PropertySource<?> ps : environment.getPropertySources()) {
                      if (ps instanceof SimpleCommandLinePropertySource) {
                          SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps;
                          mpwKey = source.getProperty("mpw.key");
                          break;
                      }
                  }
                  if(StringUtils.isEmpty(mpwKey)){
                      environment.getPropertySources().addFirst(new SimpleCommandLinePropertySource("mySpringApplicationCommandLineArgs", "--mpw.key=" + pro.getProperty("ert.version")));
                  }
              }
          
              @Override
              public int getOrder() {
                  return 0;
              }
          }

          spring.factories

          “`.properties

          ert.version=b440fe7fd55dbe26

          org.springframework.boot.env.EnvironmentPostProcessor=\

          com.itheima.SafetyEncryptProcessor

          “`

          ert.properties

          “`properties

          ert.version=2ac6625cb3188f52

          “`

          安裝到本地倉庫

          1669012678475_9.jpg

          修改mp工程添加依賴

          修改pom.xml,添加mysafe的依賴

          <dependency>
              <groupId>com.itheima</groupId>
              <artifactId>mysafe</artifactId>
              <version>1.0-SNAPSHOT</version>
          </dependency>

          4.測試結果

          去除啟動時的參數設置。再啟動后訪問頁面、效果如下:

          1669012734787_10.jpg

          總結

          1.MybatisPlus利用了springboot的配置信息增強器與SPI機制來實現對配置文件中敏感數據的解密處理。

          2.mysafe工程打成的jar包,將來就上傳到企業的內部服務器上,當密鑰變更時,重新打包即可。

          3.而我們將來布署項目到服務器上時,也肯定存在配置文件,一旦配置信息暴露,則數據庫就危險了。通過加密手段能夠讓破解者增加破解阻礙。

          4.此次練習僅做拋磚引玉作用,關于加密與解密是沒有做到那么嚴謹的,需要結合自己公司實際情況去調整。