Java 敏感信息加密處理
一、敏感信息加密處理我們要實(shí)現(xiàn)什么
系統(tǒng)往往需要將用戶敏感信息進(jìn)行加密,不同的敏感信息加密要求不同。
比如,密碼的加密,我們往往不需要是可逆的。用戶輸入密碼后,通過(guò)系統(tǒng)的加密規(guī)則,編碼后直接比對(duì)加密存儲(chǔ)的密碼,獲得比對(duì)結(jié)果即可證明用戶登錄信息合法性。
然后,有時(shí)我們?yōu)榱朔乐贡幻搸?kù)導(dǎo)致的數(shù)據(jù)泄漏,不得不對(duì)一些敏感信息(比如:身份證號(hào)、手機(jī)號(hào))進(jìn)行加密。這樣的數(shù)據(jù)不僅要求加密,還需要在展示及其他業(yè)務(wù)場(chǎng)景下完全顯示,或者掩碼顯示,這就需要我們對(duì)加密的內(nèi)容進(jìn)行解密。
二、敏感信息加密處理我做了些什么
近來(lái),項(xiàng)目中為了實(shí)現(xiàn)這個(gè)需求,做了些簡(jiǎn)單的設(shè)計(jì):
注:考慮到在維護(hù)生產(chǎn)數(shù)據(jù)時(shí)方便查詢,這里使用aes加密方式,該加密方式同mysql的aes加密結(jié)果相同,故可在sql中直接使用hex及aes_encrypt函數(shù)進(jìn)行查詢;密鹽可保存在配置文件中。
1.使用自定義注解,po的每個(gè)類中需要加密及解密的字段可添加該注解
2.聲明Base類,并實(shí)現(xiàn)encrypt和decrypt方法,方法實(shí)現(xiàn)利用java反射及自定義注解
3.所有需要用到加密及解密的實(shí)體對(duì)象,必須繼承自Base類
4.實(shí)體類加密時(shí)調(diào)用encrypt方法,解密時(shí)調(diào)用decrypt方法,如此可實(shí)現(xiàn)對(duì)該對(duì)象中敏感數(shù)據(jù)的加密解密
三、敏感信息加密實(shí)現(xiàn)
1.先看效果

注釋很清楚,先給對(duì)象設(shè)置身份證號(hào),然后執(zhí)行自加密方法,返回自己的引用,打印出來(lái)加密后該對(duì)象的json字符串;執(zhí)行自解密方法,返回自己的引用,打印出來(lái)解密后該對(duì)象的json字符串。
2.設(shè)計(jì)實(shí)現(xiàn)結(jié)構(gòu)
crypt | |--annotation | |--DecryptFiled | |--EncryptFiled |--crypt | |--EncryptDecryptInterface |--domain | |--BaseInfo | |--SimpleDomain |--utils | |--MySqlUtils
2.1先看看注解的實(shí)現(xiàn)
/**
* Created by bright on 2017/2/22.
*
* @author :
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptFiled {
String value() default "";
}
自定義注解
兩個(gè)注解的實(shí)現(xiàn)一致,注解名稱不同而已,不再貼另外一個(gè)注解的代碼。
2.2定義自加密、自解密接口
Base類實(shí)現(xiàn)該接口中的自加密自解密方法
/**
* Created by bright on 2017/2/22.
*
* @author :
*/
public interface EncryptDecryptInterface {
public <T> T encryptSelf();
public <T> T decryptSelf();
}
自定義接口
2.3MysqlUtils的實(shí)現(xiàn)
/**
* 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";//加密時(shí)編碼
private static String MYSQLUTILSKEY = "aaa";//加密密鹽
private static MySqlUtils mysqlUtils;//單例
private static Cipher encryptCipher ;//加密cipher
private static Cipher decryptChipher;//解密chipher
/**
* 該方法可用在spring項(xiàng)目中使用配置文件設(shè)置密鹽,默認(rèn)值為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);
}
}
/**
* 單例獲取方法實(shí)現(xiàn)
* @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);
}
}
/**
* 產(chǎn)生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類的實(shí)現(xiàn)
/**
* Created by bright on 2017/2/22.
*
* @author :
*/
public class BaseInfo implements Cloneable, EncryptDecryptInterface {
/**
* 拷貝一個(gè)對(duì)象,并對(duì)新對(duì)象進(jìn)行加密
* 該方法主要用在日志打印上,可防止原對(duì)象被加密而影響程序執(zhí)行
* @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("拷貝對(duì)象異常");
}
/**
* 重寫clone方法
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
/**
* 實(shí)現(xiàn)自加密
*
* @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;
}
/**
* 實(shí)現(xiàn)自解密
*
* @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一個(gè)簡(jiǎn)單的對(duì)象
/**
* 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來(lái)個(gè)調(diào)用
public class Client {
@Test
public void test(){
SimpleDomain sd = new SimpleDomain();//要進(jìn)行加密解密的實(shí)體類
sd.setId("6029131988005021537");//注入身份證號(hào)
System.out.println(JSON.toJSONString(sd.encryptSelf()));//執(zhí)行自加密后輸出
System.out.println(JSON.toJSONString(sd.decryptSelf()));//執(zhí)行自解密后輸出
}
}
Client
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
- JAVA簡(jiǎn)單實(shí)現(xiàn)MD5注冊(cè)登錄加密實(shí)例代碼
- Android、iOS和Java通用的AES128加密解密示例代碼
- JAVA 字符串加密、密碼加密實(shí)現(xiàn)方法
- Java 對(duì)稱加密幾種算法分別實(shí)現(xiàn)
- 詳解Java利用實(shí)現(xiàn)對(duì)稱加密(DES、3DES、AES)
- java實(shí)現(xiàn)md5加密示例
- java常用工具類之DES和Base64加密解密類
- Java生成MD5加密字符串代碼實(shí)例
- Java實(shí)現(xiàn)MD5加密及解密的代碼實(shí)例分享
- 分享Java常用幾種加密算法(四種)
相關(guān)文章
Spring Boot jar 啟動(dòng)時(shí)設(shè)置環(huán)境參數(shù)的操作
這篇文章主要介紹了Spring Boot jar 啟動(dòng)時(shí)設(shè)置環(huán)境參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
spring-data-redis自定義實(shí)現(xiàn)看門狗機(jī)制
redission看門狗機(jī)制是解決分布式鎖的續(xù)約問(wèn)題,本文主要介紹了spring-data-redis自定義實(shí)現(xiàn)看門狗機(jī)制,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Java實(shí)現(xiàn)Swing組件定制Button示例
這篇文章主要介紹了Java實(shí)現(xiàn)Swing組件定制Button,涉及java Swing組件Button相關(guān)屬性設(shè)置與使用操作技巧,需要的朋友可以參考下2018-01-01
java學(xué)習(xí)之JVM運(yùn)行時(shí)常量池理解
這篇文章主要介紹了java學(xué)習(xí)之JVM運(yùn)行時(shí)常量池理解,對(duì)常量池的好處以及基本類型的包裝類常量池等作了簡(jiǎn)要分析,有需要的朋友可以借鑒參考下2021-09-09
淺析mybatis和spring整合的實(shí)現(xiàn)過(guò)程
據(jù)官方的說(shuō)法,在Mybatis3問(wèn)世之前,Spring3的開(kāi)發(fā)工作就已經(jīng)完成了,所以Spring3中還是沒(méi)有對(duì)Mybatis3的支持。因此由Mybatis社區(qū)自己開(kāi)發(fā)了一個(gè)Mybatis-Spring用來(lái)滿足Mybatis用戶整合Spring的需求,下面通過(guò)Mybatis-Spring來(lái)整合Mybatis跟Spring的用法做介紹2015-10-10
Java實(shí)現(xiàn)簡(jiǎn)易版猜燈謎游戲的示例代碼
燈謎是中秋節(jié)傳統(tǒng)的活動(dòng)之一,而現(xiàn)代化的方式則是將其制作成一個(gè)小游戲,讓用戶在游戲的過(guò)程中猜燈謎,互動(dòng)體驗(yàn)更佳,所以本文小編就用Java制作一款猜燈謎小游戲吧2023-09-09
java中URLEncoder.encode與URLDecoder.decode處理url特殊參數(shù)的方法
這篇文章主要給大家介紹了關(guān)于java中URLEncoder.encode與URLDecoder.decode處理url特殊參數(shù)的方法,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-03-03
一文總結(jié)RabbitMQ中的消息確認(rèn)機(jī)制
RabbitMQ消息確認(rèn)機(jī)制指的是在消息傳遞過(guò)程中,發(fā)送方發(fā)送消息后,接收方需要對(duì)消息進(jìn)行確認(rèn),以確保消息被正確地接收和處理,本文為大家整理了RabbitMQ中的消息確認(rèn)機(jī)制,需要的可以參考一下2023-06-06

