Java 敏感信息加密处理

发布时间 - 2026-01-11 00:13:36    点击率:

一、敏感信息加密处理我们要实现什么

系统往往需要将用户敏感信息进行加密,不同的敏感信息加密要求不同。

比如,密码的加密,我们往往不需要是可逆的。用户输入密码后,通过系统的加密规则,编码后直接比对加密存储的密码,获得比对结果即可证明用户登录信息合法性。

然后,有时我们为了防止被脱库导致的数据泄漏,不得不对一些敏感信息(比如:身份证号、手机号)进行加密。这样的数据不仅要求加密,还需要在展示及其他业务场景下完全显示,或者掩码显示,这就需要我们对加密的内容进行解密。

二、敏感信息加密处理我做了些什么

近来,项目中为了实现这个需求,做了些简单的设计:

注:考虑到在维护生产数据时方便查询,这里使用aes加密方式,该加密方式同mysql的aes加密结果相同,故可在sql中直接使用hex及aes_encrypt函数进行查询;密盐可保存在配置文件中。

1.使用自定义注解,po的每个类中需要加密及解密的字段可添加该注解

2.声明Base类,并实现encrypt和decrypt方法,方法实现利用java反射及自定义注解

3.所有需要用到加密及解密的实体对象,必须继承自Base类

4.实体类加密时调用encrypt方法,解密时调用decrypt方法,如此可实现对该对象中敏感数据的加密解密

三、敏感信息加密实现

1.先看效果

注释很清楚,先给对象设置身份证号,然后执行自加密方法,返回自己的引用,打印出来加密后该对象的json字符串;执行自解密方法,返回自己的引用,打印出来解密后该对象的json字符串。

2.设计实现结构

crypt
   |
   |--annotation
   |    |--DecryptFiled
   |    |--EncryptFiled
   |--crypt
   |    |--EncryptDecryptInterface
   |--domain
   |    |--BaseInfo
   |    |--SimpleDomain
   |--utils
   |    |--MySqlUtils

2.1先看看注解的实现

/**
 * Created by bright on 2017/2/22.
 *
 * @author :
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptFiled {
  String value() default "";
}

自定义注解

两个注解的实现一致,注解名称不同而已,不再贴另外一个注解的代码。

2.2定义自加密、自解密接口

Base类实现该接口中的自加密自解密方法

/**
 * Created by bright on 2017/2/22.
 *
 * @author :
 */
public interface EncryptDecryptInterface {
  public <T> T encryptSelf();
  public <T> T decryptSelf();
}

自定义接口

2.3MysqlUtils的实现

/**
 * Created by bright on 2017/2/22.
 *
 * @author :
 */
@Component
public class MySqlUtils {
  private static final String ENCRYPTTYPE= "AES";//加密方式
  private static final String ENCODING = "UTF-8";//加密时编码

  private static String MYSQLUTILSKEY = "aaa";//加密密盐
  private static MySqlUtils mysqlUtils;//单例
  private static Cipher encryptCipher ;//加密cipher
  private static Cipher decryptChipher;//解密chipher
  /**
   * 该方法可用在spring项目中使用配置文件设置密盐,默认值为123
   * @param key
   */
  @Value("${mysql.column.crypt.key:123}")
  public void setMysqlutilskey(String key){
    MySqlUtils.MYSQLUTILSKEY = key;
  }
  /**
   * encryptCipher、decryptChipher初始化
   */
  public static void init(){
    try {
      encryptCipher = Cipher.getInstance(ENCRYPTTYPE);
      decryptChipher = Cipher.getInstance(ENCRYPTTYPE);
      encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey(MYSQLUTILSKEY, ENCODING));
      decryptChipher.init(Cipher.DECRYPT_MODE, generateMySQLAESKey(MYSQLUTILSKEY, ENCODING));
    } catch (InvalidKeyException e) {
      throw new RuntimeException(e);
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException(e);
    } catch (NoSuchPaddingException e) {
      throw new RuntimeException(e);
    }
  }
  /**
   * 单例获取方法实现
   * @return
   */
  public synchronized static MySqlUtils getInstance(){
    if(mysqlUtils == null){
      mysqlUtils = new MySqlUtils();
      init();
    }
    return mysqlUtils;
  }
  /**
   * 加密算法
   * @param encryptString
   * @return
   */
  public String mysqlAESEncrypt(String encryptString) {
    try{
      return new String(Hex.encodeHex(encryptCipher.doFinal(encryptString.getBytes(ENCODING)))).toUpperCase();
    } catch (BadPaddingException e) {
      throw new RuntimeException(e);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    } catch (IllegalBlockSizeException e) {
      throw new RuntimeException(e);
    }
  }
  /**
   * 解密算法
   * @param decryptString
   * @return
   */
  public String mysqlAESDecrypt(String decryptString){
    try {
      return new String(decryptChipher.doFinal(Hex.decodeHex(decryptString.toCharArray())));
    } catch (DecoderException nspe) {
      throw new RuntimeException(nspe);
    } catch (BadPaddingException nsae) {
      throw new RuntimeException(nsae);
    } catch (IllegalBlockSizeException ike) {
      throw new RuntimeException(ike);
    }
  }
  /**
   * 产生mysql-aes_encrypt
   * @param key 加密的密盐
   * @param encoding 编码
   * @return
   */
  public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) {
    try {
      final byte[] finalKey = new byte[16];
      int i = 0;
      for(byte b : key.getBytes(encoding))
        finalKey[i++%16] ^= b;
      return new SecretKeySpec(finalKey, "AES");
    } catch(UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }
}

MysqlUtils

2.4BaseInfo类的实现

/**
 * Created by bright on 2017/2/22.
 *
 * @author :
 */
public class BaseInfo implements Cloneable, EncryptDecryptInterface {
  /**
   * 拷贝一个对象,并对新对象进行加密
   * 该方法主要用在日志打印上,可防止原对象被加密而影响程序执行
   * @param <T>
   * @return
   */
  public <T extends BaseInfo> T cloneAndEncrypt() {
    T cloneT = null;
    try {
      cloneT = (T) this.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
      return null;
    }
    if(cloneT !=null)
      return cloneT.encryptSelf();
    throw new RuntimeException("拷贝对象异常");
  }
  /**
   * 重写clone方法
   * @return
   * @throws CloneNotSupportedException
   */
  @Override
  protected Object clone() throws CloneNotSupportedException {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
      return null;
    }
  }
  /**
   * 实现自加密
   *
   * @param <T>
   * @return
   */
  public <T> T encryptSelf() {
    Field[] declaredFields = this.getClass().getDeclaredFields();
    try {
      if (declaredFields != null && declaredFields.length > 0) {
        for (Field field : declaredFields) {
          if (field.isAnnotationPresent(EncryptFiled.class) && field.getType().toString().endsWith("String")) {
            field.setAccessible(true);
            String fieldValue = (String) field.get(this);
            if (StringUtils.isNotEmpty(fieldValue)) {
              field.set(this, MySqlUtils.getInstance().mysqlAESEncrypt(fieldValue));
            }
            field.setAccessible(false);
          }
        }
      }
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
    return (T) this;
  }
  /**
   * 实现自解密
   *
   * @param <T>
   * @return
   */
  public <T> T decryptSelf() {
    Field[] declaredFields = this.getClass().getDeclaredFields();
    try {
      if (declaredFields != null && declaredFields.length > 0) {
        for (Field field : declaredFields) {
          if (field.isAnnotationPresent(DecryptFiled.class) && field.getType().toString().endsWith("String")) {
            field.setAccessible(true);
            String fieldValue = (String)field.get(this);
            if(StringUtils.isNotEmpty(fieldValue)) {
              field.set(this, MySqlUtils.getInstance().mysqlAESDecrypt(fieldValue));
            }
          }
        }
      }
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
    return (T) this;
  }
}

BaseInfo

2.5一个简单的对象

/**
 * Created by bright on 2017/2/22.
 *
 * @author :
 */
public class SimpleDomain extends BaseInfo{
  @EncryptFiled
  @DecryptFiled
  private String id;
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
}

SimpleDomain

2.6来个调用

public class Client {
  @Test
  public void test(){
    SimpleDomain sd = new SimpleDomain();//要进行加密解密的实体类
    sd.setId("6029131988005021537");//注入身份证号
    System.out.println(JSON.toJSONString(sd.encryptSelf()));//执行自加密后输出
    System.out.println(JSON.toJSONString(sd.decryptSelf()));//执行自解密后输出
  }
}

Client

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# java  # 敏感信息加密  # 敏感信息处理  # JAVA简单实现MD5注册登录加密实例代码  # Android、iOS和Java通用的AES128加密解密示例代码  # JAVA 字符串加密、密码加密实现方法  # Java 对称加密几种算法分别实现  # 详解Java利用实现对称加密(DES、3DES、AES)  # java实现md5加密示例  # java常用工具类之DES和Base64加密解密类  # Java生成MD5加密字符串代码实例  # Java实现MD5加密及解密的代码实例分享  # 分享Java常用几种加密算法(四种)  # 自定义  # 自己的  # 时方  # 用在  # 配置文件  # 比对  # 打印出来  # 加密解密  # 些什么  # 要在  # 这就  # 可在  # 考虑到  # 实体类  # 重写  # 并对  # 很清楚  # 另外一个  # 不需  # 来个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何快速搭建高效简练网站?  如何在万网自助建站中设置域名及备案?  如何确保FTP站点访问权限与数据传输安全?  想要更高端的建设网站,这些原则一定要坚持!  香港服务器如何优化才能显著提升网站加载速度?  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  如何快速搭建虚拟主机网站?新手必看指南  WEB开发之注册页面验证码倒计时代码的实现  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  如何快速生成可下载的建站源码工具?  制作电商网页,电商供应链怎么做?  千库网官网入口推荐 千库网设计创意平台入口  如何在不使用负向后查找的情况下匹配特定条件前的换行符  JS弹性运动实现方法分析  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  JavaScript中的标签模板是什么_它如何扩展字符串功能  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  Linux安全能力提升路径_长期防护思维说明【指导】  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  Laravel如何使用Blade模板引擎?(完整语法和示例)  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  如何在景安服务器上快速搭建个人网站?  Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】  如何快速搭建高效服务器建站系统?  Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境  LinuxCD持续部署教程_自动发布与回滚机制  Java类加载基本过程详细介绍  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  Java遍历集合的三种方式  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  如何在IIS7中新建站点?详细步骤解析  如何快速查询网站的真实建站时间?  详解Android中Activity的四大启动模式实验简述  如何在VPS电脑上快速搭建网站?  如何在Tomcat中配置并部署网站项目?  Android利用动画实现背景逐渐变暗  北京的网站制作公司有哪些,哪个视频网站最好?  如何在服务器上配置二级域名建站?  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?