积分商城用户数据加密改造实战

1. 项目背景

在积分商城系统中,保护用户个人信息很重要。因此,需要对不定长字符串类型的系统基础表结构中需要加密的字段进行加密处理,保证数据安全性。

同时,需要保证加密前后数据转换后,不影响环境性展示和上线用户体验。

2. 技术集成总结

  • 实现策略: 使用 AES 加密算法,将敏感字段加密后存储,同时保留原始数据处理方式以实现同时兼容。
  • 解决方案: 通过 MyBatis TypeHandler 解耦存取过程,自动将某些指定字段进行加密和解密操作,无需修改上应应用逻辑。
  • 分步执行:
    • 分析需加密字段
    • 编写AES加密/解密公共类
    • 实现MyBatis TypeHandler
    • 数据移植工具脚本,实现旧数据加密

3. 具体技术进程

3.1 分析字段

根据数据存储结构,确定哪些字段需要加密:

  • 用户姓名
  • 电话号码
  • 邮箱
  • 身份证号

3.2 AES加密工具

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AesUtil {
    private static final String ALGORITHM = "AES";
    private static final String KEY = "1234567890abcdef"; // 16位密钥

    public static String encrypt(String value) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encrypted) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] decoded = Base64.getDecoder().decode(encrypted);
        byte[] original = cipher.doFinal(decoded);
        return new String(original);
    }
}

3.3 实现MyBatis TypeHandler

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class EncryptTypeHandler extends BaseTypeHandler<String> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        try {
            ps.setString(i, AesUtil.encrypt(parameter));
        } catch (Exception e) {
            throw new SQLException("Encryption failed", e);
        }
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return AesUtil.decrypt(rs.getString(columnName));
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return AesUtil.decrypt(rs.getString(columnIndex));
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return AesUtil.decrypt(cs.getString(columnIndex));
        } catch (Exception e) {
            return null;
        }
    }
}

配合 MyBatis Mapper 使用:

<result property="phone" column="phone" typeHandler="xxx.EncryptTypeHandler" />

3.4 数据移植脚本

写一个移植脚本,将旧数据转为加密形式。

基本步骤:

  • 找出所有旧数据
  • 调用AesUtil进行加密
  • 更新回原数据表

示例:

List<User> users = userDao.findAll();
for (User user : users) {
    String encryptedPhone = AesUtil.encrypt(user.getPhone());
    userDao.updatePhone(user.getId(), encryptedPhone);
}

4. 实践结果

完成数据加密改造后,系统正常运行,上线用户体验无明显变化,同时提升了数据安全性,成功满足后续安全管控需求。


整体过程中,最关键的是定制好规范,遵循加密协议,确保各组件互相兼容。实际工程中,还可考虑增加片段加密(如通过指定段名来分类加密),更精精刻控制实施效果。

Ge Yuxu • AI & Engineering

脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实,仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
    • 文中所示任何标识符并不对应实际生产环境中的名称或编号。
    • 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
    • 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。

Data Desensitization Notice: All table names, field names, API endpoints, variable names, IP addresses, and sample data appearing in this article are fictitious and intended solely to illustrate technical concepts and implementation steps. The sample code is not actual company code. The proposed solutions are not complete or actual company solutions but are summarized from the author's memory for technical learning and discussion.
    • Any identifiers shown in the text do not correspond to names or numbers in any actual production environment.
    • Sample SQL, scripts, code, and data are for demonstration purposes only, do not contain real business data, and lack the full context required for direct execution or reproduction.
    • Readers who wish to reference the solutions in this article for actual projects should adapt them to their own business scenarios and data security standards, using configurations that comply with internal naming and access control policies.

版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
    • 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
    • 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。

Copyright Notice: The copyright of this article belongs to the original author. Without prior written permission from the author, no entity or individual may copy, reproduce, excerpt, or use it for commercial purposes in any way.
    • For non-commercial citation or reproduction of this content, attribution must be given, and the integrity of the content must be maintained.
    • The author reserves the right to pursue legal action against any legal disputes arising from the commercial use, alteration, or improper citation of this article's content.

Copyright © 1989–Present Ge Yuxu. All Rights Reserved.