成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

50行代碼,搞定敏感數據讀寫!

開發 前端
在實際的軟件系統開發過程中,由于業務的需求,在代碼層面實現數據的脫敏還是遠遠不夠的,往往還需要在數據庫層面針對某些關鍵性的敏感信息,那在實際的研發過程中,我們如何實踐呢?

一、介紹

在實際的軟件系統開發過程中,由于業務的需求,在代碼層面實現數據的脫敏還是遠遠不夠的,往往還需要在數據庫層面針對某些關鍵性的敏感信息,例如:身份證號、銀行卡號、手機號、工資等信息進行加密存儲,實現真正意義的數據混淆脫敏,以滿足信息安全的需要。

那在實際的研發過程中,我們如何實踐呢?

二、方案實踐

在此,提供三套方案以供大家選擇。

  • 通過 SQL 函數實現加解密
  • 對 SQL 進行解析攔截,實現數據加解密
  • 自定義一套脫敏工具

1. 通過 SQL 函數實現加解密

最簡單的方法,莫過于直接在數據庫層面操作,通過函數對某個字段進行加、解密,例如如下這個案例!

  1. -- 對“你好,世界”進行加密 
  2. select   HEX(AES_ENCRYPT('你好,世界','ABC123456')); 
  3.  
  4. -- 解密,輸出:你好,世界 
  5. select  AES_DECRYPT(UNHEX('A174E3C13FE16AA0FD071A4BBD7CD7C5'),'ABC123456'); 

采用MySQL內置的AES協議加、解密函數,密鑰是ABC123456,可以很輕松的對某個字段實現加、解密。

如果是很小的需求,需要加密的數據就是指定的信息,此方法可行。

但是當需要加密的表字段非常多的時候,這個使用起來就比較雞肋了,例如我想更改加密算法或者不同的部署環境配置不同的密鑰,這個時候就不得不把所有的代碼進行更改一遍。

2. 對 SQL 進行解析攔截,實現數據加解密

通過上面的方案,我們發現最大的痛點就是加密算法和密鑰都寫死在SQL上了,因此我們可以將這塊的服務從抽出來,在JDBC層面,當sql執行的時候,對其進行攔截處理。

Apache ShardingSphere 框架下的數據脫敏模塊,它就可以幫助我們實現這一需求,如果你是SpringBoot項目,可以實現無縫集成,對原系統的改造會非常少。

下面以用戶表為例,我們來看看采用ShardingSphere如何實現!

(1) 創建用戶表

  1. CREATE TABLE user ( 
  2.   id bigint(20) NOT NULL COMMENT '用戶ID', 
  3.   email varchar(255)  NOT NULL DEFAULT '' COMMENT '郵件', 
  4.   nick_name varchar(255)  DEFAULT NULL COMMENT '昵稱', 
  5.   pass_word varchar(255)  NOT NULL DEFAULT '' COMMENT '二次密碼', 
  6.   reg_time varchar(255)  NOT NULL DEFAULT '' COMMENT '注冊時間', 
  7.   user_name varchar(255)  NOT NULL DEFAULT '' COMMENT '用戶名', 
  8.   salary varchar(255) DEFAULT NULL COMMENT '基本工資', 
  9.   PRIMARY KEY (id) USING BTREE 
  10. ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

(2) 創建 springboot 項目并添加依賴包

  1. <dependencies> 
  2.     <!--spring boot核心--> 
  3.     <dependency> 
  4.         <groupId>org.springframework.boot</groupId> 
  5.         <artifactId>spring-boot-starter</artifactId> 
  6.     </dependency> 
  7.     <!--spring boot 測試--> 
  8.     <dependency> 
  9.         <groupId>org.springframework.boot</groupId> 
  10.         <artifactId>spring-boot-starter-test</artifactId> 
  11.         <scope>test</scope> 
  12.     </dependency> 
  13.     <!--springmvc web--> 
  14.     <dependency> 
  15.         <groupId>org.springframework.boot</groupId> 
  16.         <artifactId>spring-boot-starter-web</artifactId> 
  17.     </dependency> 
  18.     <!--mysql 數據源--> 
  19.     <dependency> 
  20.         <groupId>mysql</groupId> 
  21.         <artifactId>mysql-connector-java</artifactId> 
  22.     </dependency> 
  23.     <!--mybatis 支持--> 
  24.     <dependency> 
  25.         <groupId>org.mybatis.spring.boot</groupId> 
  26.         <artifactId>mybatis-spring-boot-starter</artifactId> 
  27.         <version>2.0.0</version> 
  28.     </dependency>  
  29.     <!--shardingsphere數據分片、脫敏工具--> 
  30.     <dependency> 
  31.         <groupId>org.apache.shardingsphere</groupId> 
  32.         <artifactId>sharding-jdbc-spring-boot-starter</artifactId> 
  33.         <version>4.1.0</version> 
  34.     </dependency> 
  35.     <dependency> 
  36.         <groupId>org.apache.shardingsphere</groupId> 
  37.         <artifactId>sharding-jdbc-spring-namespace</artifactId> 
  38.         <version>4.1.0</version> 
  39.     </dependency> 
  40. </dependencies> 

(3) 添加脫敏配置

在application.properties文件中,添加shardingsphere相關配置,即可實現針對某個表進行脫敏。

  1. server.port=8080 
  2.  
  3. loglogging.path=log 
  4.  
  5. #shardingsphere數據源集成 
  6. spring.shardingsphere.datasource.name=ds 
  7. spring.shardingsphere.datasource.ds.type=com.zaxxer.hikari.HikariDataSource 
  8. spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.cj.jdbc.Driver 
  9. spring.shardingsphere.datasource.ds.jdbc-url=jdbc:mysql://127.0.0.1:3306/test 
  10. spring.shardingsphere.datasource.ds.username=xxxx 
  11. spring.shardingsphere.datasource.ds.password=xxxx 
  12.  
  13. #加密方式、密鑰配置 
  14. spring.shardingsphere.encrypt.encryptors.encryptor_aes.type=aes 
  15. spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value=hkiqAXU6Ur5fixGHaO4Lb2V2ggausYwW 
  16. #plainColumn表示明文列,cipherColumn表示脫敏列 
  17. springspring.shardingsphere.encrypt.tables.user.columns.salary.plainColumn
  18. spring.shardingsphere.encrypt.tables.user.columns.salary.cipherColumn=salary 
  19. #springspring.shardingsphere.encrypt.tables.user.columns.pass_word.assistedQueryColumn
  20. spring.shardingsphere.encrypt.tables.user.columns.salary.encryptor=encryptor_aes 
  21.  
  22. #sql打印 
  23. spring.shardingsphere.props.sql.show=true 
  24. spring.shardingsphere.props.query.with.cipher.column=true 
  25.  
  26.  
  27. #基于xml方法的配置 
  28. mybatis.mapper-locations=classpath:mapper/*.xml 

其中下面的配置信息是關鍵的一部,spring.shardingsphere.encrypt.tables是指要脫敏的表,user是表名,salary表示user表中的真實列,其中plainColumn指的是明文列,cipherColumn指的是脫敏列,如果是新工程,只需要配置脫敏列即可!

  1. springspring.shardingsphere.encrypt.tables.user.columns.salary.plainColumn
  2. spring.shardingsphere.encrypt.tables.user.columns.salary.cipherColumn=salary 
  3. #springspring.shardingsphere.encrypt.tables.user.columns.pass_word.assistedQueryColumn
  4. spring.shardingsphere.encrypt.tables.user.columns.salary.encryptor=encryptor_aes 

(4) 編寫數據持久層

  1. <mapper namespace="com.example.shardingsphere.mapper.UserMapperXml" > 
  2.  
  3.     <resultMap id="BaseResultMap" type="com.example.shardingsphere.entity.UserEntity" > 
  4.         <id column="id" property="id" jdbcType="BIGINT" /> 
  5.         <result column="email" property="email" jdbcType="VARCHAR" /> 
  6.         <result column="nick_name" property="nickName" jdbcType="VARCHAR" /> 
  7.         <result column="pass_word" property="passWord" jdbcType="VARCHAR" /> 
  8.         <result column="reg_time" property="regTime" jdbcType="VARCHAR" /> 
  9.         <result column="user_name" property="userName" jdbcType="VARCHAR" /> 
  10.         <result column="salary" property="salary" jdbcType="VARCHAR" /> 
  11.     </resultMap> 
  12.  
  13.     <select id="findAll" resultMap="BaseResultMap"> 
  14.         SELECT * FROM user 
  15.     </select> 
  16.      
  17.     <insert id="insert" parameterType="com.example.shardingsphere.entity.UserEntity"> 
  18.         INSERT INTO user(id,email,nick_name,pass_word,reg_time,user_name, salary) 
  19.         VALUES(#{id},#{email},#{nickName},#{passWord},#{regTime},#{userName}, #{salary}) 
  20.     </insert> 
  21. </mapper> 
  1. public interface UserMapperXml { 
  2.  
  3.  
  4.     /** 
  5.      * 查詢所有的信息 
  6.      * @return 
  7.      */ 
  8.     List<UserEntity> findAll(); 
  9.  
  10.     /** 
  11.      * 新增數據 
  12.      * @param user 
  13.      */ 
  14.     void insert(UserEntity user); 
  1. public class UserEntity { 
  2.  
  3.     private Long id; 
  4.  
  5.     private String email; 
  6.  
  7.     private String nickName; 
  8.  
  9.     private String passWord; 
  10.  
  11.     private String regTime; 
  12.  
  13.     private String userName; 
  14.  
  15.     private String salary; 
  16.  
  17.  //省略set、get... 
  18.  

(5) 最后我們來測試一下程序運行情況

編寫啟用服務程序:

  1. @SpringBootApplication 
  2. @MapperScan("com.example.shardingsphere.mapper") 
  3. public class ShardingSphereApplication { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(ShardingSphereApplication.class, args); 
  7.     } 

編寫單元測試:

  1. @RunWith(SpringJUnit4ClassRunner.class) 
  2. @SpringBootTest(classes = ShardingSphereApplication.class) 
  3. public class UserTest { 
  4.  
  5.     @Autowired 
  6.     private UserMapperXml userMapperXml; 
  7.  
  8.     @Test 
  9.     public void insert() throws Exception { 
  10.         UserEntity entity = new UserEntity(); 
  11.         entity.setId(3l); 
  12.         entity.setEmail("123@123.com"); 
  13.         entity.setNickName("阿三"); 
  14.         entity.setPassWord("123"); 
  15.         entity.setRegTime("2021-10-10 00:00:00"); 
  16.         entity.setUserName("張三"); 
  17.         entity.setSalary("2500"); 
  18.         userMapperXml.insert(entity); 
  19.     } 
  20.  
  21.     @Test 
  22.     public void query() throws Exception { 
  23.         List<UserEntity> dataList = userMapperXml.findAll(); 
  24.         System.out.println(JSON.toJSONString(dataList)); 
  25.     } 

插入數據后,如下圖,數據庫存儲的數據已被加密!

我們繼續來看看,運行查詢服務,結果如下圖,數據被成功解密!

采用配置方式,最大的好處就是直接通過配置脫敏列就可以完成對某些數據表字段的脫敏,非常方便。

3. 自定義一套脫敏工具

當然,有的同學可能會覺得shardingsphere配置雖然簡單,但是還是不放心,里面的很多規則自己無法掌控,想自己開發一套數據庫的脫敏工具。

方案也是有的,例如如下這套實踐方案,以Mybatis為例:

  • 首先編寫一套加解密的算法工具類
  • 通過Mybatis的typeHandler插件,實現特定字段的加解密

實踐過程如下:

(1) 加解密工具類

  1. public class AESCryptoUtil { 
  2.  
  3.     private static final Logger log = LoggerFactory.getLogger(AESCryptoUtil.class); 
  4.  
  5.     private static final String DEFAULT_ENCODING = "UTF-8"
  6.     private static final String AES = "AES"
  7.  
  8.  
  9.     /** 
  10.      * 加密 
  11.      * 
  12.      * @param content 需要加密內容 
  13.      * @param key     任意字符串 
  14.      * @return 
  15.      * @throws Exception 
  16.      */ 
  17.     public static String encryptByRandomKey(String content, String key) { 
  18.         try { 
  19.             //構造密鑰生成器,生成一個128位的隨機源,產生原始對稱密鑰 
  20.             KeyGenerator keygen = KeyGenerator.getInstance(AES); 
  21.             SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 
  22.             random.setSeed(key.getBytes()); 
  23.             keygen.init(128, random); 
  24.             byte[] raw = keygen.generateKey().getEncoded(); 
  25.             SecretKey secretKey = new SecretKeySpec(raw, AES); 
  26.             Cipher cipher = Cipher.getInstance(AES); 
  27.             cipher.init(Cipher.ENCRYPT_MODE, secretKey); 
  28.             byte[] encrypted = cipher.doFinal(content.getBytes("utf-8")); 
  29.             return Base64.getEncoder().encodeToString(encrypted); 
  30.         } catch (Exception e) { 
  31.             log.warn("AES加密失敗,參數:{},錯誤信息:{}", content, e); 
  32.             return ""; 
  33.         } 
  34.     } 
  35.  
  36.     public static String decryptByRandomKey(String content, String key) { 
  37.         try { 
  38.             //構造密鑰生成器,生成一個128位的隨機源,產生原始對稱密鑰 
  39.             KeyGenerator generator = KeyGenerator.getInstance(AES); 
  40.             SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 
  41.             random.setSeed(key.getBytes()); 
  42.             generator.init(128, random); 
  43.             SecretKey secretKey = new SecretKeySpec(generator.generateKey().getEncoded(), AES); 
  44.             Cipher cipher = Cipher.getInstance(AES); 
  45.             cipher.init(Cipher.DECRYPT_MODE, secretKey); 
  46.             byte[] encrypted = Base64.getDecoder().decode(content); 
  47.             byte[] original = cipher.doFinal(encrypted); 
  48.             return new String(original, DEFAULT_ENCODING); 
  49.         } catch (Exception e) { 
  50.             log.warn("AES解密失敗,參數:{},錯誤信息:{}", content, e); 
  51.             return ""; 
  52.         } 
  53.     } 
  54.  
  55.     public static void main(String[] args) { 
  56.         String encryptResult = encryptByRandomKey("Hello World", "123456"); 
  57.         System.out.println(encryptResult); 
  58.         String decryptResult = decryptByRandomKey(encryptResult, "123456"); 
  59.         System.out.println(decryptResult); 
  60.     } 

2.3.2、針對 salary 字段進行單獨解析

  1. <mapper namespace="com.example.shardingsphere.mapper.UserMapperXml" > 
  2.  
  3.     <resultMap id="BaseResultMap" type="com.example.shardingsphere.entity.UserEntity" > 
  4.         <id column="id" property="id" jdbcType="BIGINT" /> 
  5.         <result column="email" property="email" jdbcType="VARCHAR" /> 
  6.         <result column="nick_name" property="nickName" jdbcType="VARCHAR" /> 
  7.         <result column="pass_word" property="passWord" jdbcType="VARCHAR" /> 
  8.         <result column="reg_time" property="regTime" jdbcType="VARCHAR" /> 
  9.         <result column="user_name" property="userName" jdbcType="VARCHAR" /> 
  10.         <result column="salary" property="salary" jdbcType="VARCHAR" 
  11.                 typeHandler="com.example.shardingsphere.handle.EncryptDataRuleTypeHandler"/> 
  12.     </resultMap> 
  13.  
  14.     <select id="findAll" resultMap="BaseResultMap"> 
  15.         select * from user 
  16.     </select> 
  17.      
  18.     <insert id="insert" parameterType="com.example.shardingsphere.entity.UserEntity"> 
  19.         INSERT INTO user(id,email,nick_name,pass_word,reg_time,user_name, salary) 
  20.         VALUES( 
  21.         #{id}, 
  22.         #{email}, 
  23.         #{nickName}, 
  24.         #{passWord}, 
  25.         #{regTime}, 
  26.         #{userName}, 
  27.         #{salary,jdbcType=INTEGER,typeHandler=com.example.shardingsphere.handle.EncryptDataRuleTypeHandler}) 
  28.     </insert> 
  29. </mapper> 

EncryptDataRuleTypeHandler解析器,內容如下:

  1. public class EncryptDataRuleTypeHandler implements TypeHandler<String> { 
  2.  
  3.     private static final String EMPTY = ""
  4.  
  5.     /** 
  6.      * 寫入數據 
  7.      * @param preparedStatement 
  8.      * @param i 
  9.      * @param data 
  10.      * @param jdbcType 
  11.      * @throws SQLException 
  12.      */ 
  13.     @Override 
  14.     public void setParameter(PreparedStatement preparedStatement, int i, String data, JdbcType jdbcType) throws SQLException { 
  15.         if (StringUtils.isEmpty(data)) { 
  16.             preparedStatement.setString(i, EMPTY); 
  17.         } else { 
  18.             preparedStatement.setString(i, AESCryptoUtil.encryptByRandomKey(data, "123456")); 
  19.         } 
  20.     } 
  21.  
  22.     /** 
  23.      * 讀取數據 
  24.      * @param resultSet 
  25.      * @param columnName 
  26.      * @return 
  27.      * @throws SQLException 
  28.      */ 
  29.     @Override 
  30.     public String getResult(ResultSet resultSet, String columnName) throws SQLException { 
  31.         return decrypt(resultSet.getString(columnName)); 
  32.     } 
  33.  
  34.     /** 
  35.      * 讀取數據 
  36.      * @param resultSet 
  37.      * @param columnIndex 
  38.      * @return 
  39.      * @throws SQLException 
  40.      */ 
  41.     @Override 
  42.     public String getResult(ResultSet resultSet, int columnIndex) throws SQLException { 
  43.         return decrypt(resultSet.getString(columnIndex)); 
  44.     } 
  45.  
  46.     /** 
  47.      * 讀取數據 
  48.      * @param callableStatement 
  49.      * @param columnIndex 
  50.      * @return 
  51.      * @throws SQLException 
  52.      */ 
  53.     @Override 
  54.     public String getResult(CallableStatement callableStatement, int columnIndex) throws SQLException { 
  55.         return decrypt(callableStatement.getString(columnIndex)); 
  56.     } 
  57.  
  58.     /** 
  59.      * 對數據進行解密 
  60.      * @param data 
  61.      * @return 
  62.      */ 
  63.     private String decrypt(String data) { 
  64.         return AESCryptoUtil.decryptByRandomKey(data, "123456"); 
  65.     } 

(3) 單元測試

再次運行單元測試,程序讀寫正常!

 

通過如下的方式,也可以實現對數據表中某個特定字段進行數據脫敏處理!

三、小結

因業務的需求,當需要對某些數據表字段進行脫敏處理的時候,有個細節很容易遺漏,那就是字典類型,例如salary字段,根據常規,很容易想到使用數字類型,但是卻不是,要知道加密之后的數據都是一串亂碼,數字類型肯定是無法存儲字符串的,因此在定義的時候,這個要留心一下。

其次,很多同學可能會覺得,這個也不能防范比人竊取數據啊!

如果加密使用的密鑰和數據都在一個項目里面,答案是肯定的,你可以隨便解析任何人的數據。因此在實際的處理上,這個更多的是在流程上做變化。例如如下方式:

  • 首先,加密采用的密鑰會在另外一個單獨的服務來存儲管理,保證密鑰不輕易泄露出去,最重要的是加密的數據不輕易被別人解密。
  • 其次,例如某些人想要訪問誰的工資條數據,那么就需要做二次密碼確認,也就是輸入自己的密碼才能獲取,可以進一步防止研發人員隨意通過接口方式讀取數據。
  • 最后就是,杜絕代碼留漏洞。

以上三套方案,都可以幫助大家實現數據庫字段數據的脫敏,希望能幫助到大家,謝謝欣賞!

 

 

責任編輯:趙寧寧 來源: Java極客技術
相關推薦

2010-09-25 08:55:29

2023-10-23 10:39:05

2020-10-25 09:04:46

數據加密數據泄露攻擊

2023-06-27 07:26:36

汽車之家敏感數據治理

2021-09-16 10:11:15

Dataphin 數據保護

2023-10-30 15:35:05

數據安全數據驅動

2020-04-16 08:00:00

Ansible Vau敏感數據加密

2024-03-05 09:40:35

2011-08-01 14:36:06

加密RSA

2024-01-01 15:53:25

2012-04-12 14:45:12

賽門鐵克云南電網

2020-12-20 17:30:17

數據匿名化敏感數據數據庫

2025-01-21 14:48:39

2012-07-03 11:35:02

數據安全

2020-07-06 09:21:52

云平臺云安全公共云

2021-09-18 10:06:06

數據安全隱私計算大數據

2018-09-14 14:48:01

2013-09-12 13:23:06

2023-07-21 12:48:37

2024-09-27 12:27:31

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美视频在线 | 国产区视频在线观看 | 亚洲毛片在线 | 国产aⅴ爽av久久久久久久 | 免费精品一区 | av一区二区三区四区 | 日本三级精品 | 九九热在线视频观看这里只有精品 | 久久久av中文字幕 | 日韩精品成人av | 成人欧美一区二区三区 | 国产精品久久福利 | 黄页网址在线观看 | 国产精品美女久久久久久免费 | 狠狠干狠狠操 | 久色网| 国产羞羞视频在线观看 | 久久久久久国产精品 | 国产不卡一区 | 91视频日本| 欧美日韩国产一区 | 亚洲欧美日韩在线 | 香蕉视频久久久 | 亚洲一区二区三区免费观看 | 国产精品成人一区二区三区 | 在线视频中文字幕 | 国产精品久久久久久婷婷天堂 | 最新黄色毛片 | 成人av播放 | 中文字幕国产精品 | 一二三四在线视频观看社区 | 国产激情第一页 | 日韩精品久久一区二区三区 | 妹子干综合 | 久久久国产一区二区三区 | h视频在线观看免费 | 日韩在线一区二区 | 欧美free性 | 黄色香蕉视频在线观看 | 精品亚洲91 | 亚洲精品免费视频 |