一、敏感信息加密處理我們要實現什么
系統往往需要將用戶敏感信息進行加密,不同的敏感信息加密要求不同。
比如,密碼的加密,我們往往不需要是可逆的。用戶輸入密碼后,通過系統的加密規則,編碼后直接比對加密存儲的密碼,獲得比對結果即可證明用戶登錄信息合法性。
然后,有時我們為了防止被脫庫導致的數據泄漏,不得不對一些敏感信息(比如:身份證號、手機號)進行加密。這樣的數據不僅要求加密,還需要在展示及其他業務場景下完全顯示,或者掩碼顯示,這就需要我們對加密的內容進行解密。
二、敏感信息加密處理我做了些什么
近來,項目中為了實現這個需求,做了些簡單的設計:
注:考慮到在維護生產數據時方便查詢,這里使用aes加密方式,該加密方式同mysql的aes加密結果相同,故可在sql中直接使用hex及aes_encrypt函數進行查詢;密鹽可保存在配置文件中。
1.使用自定義注解,po的每個類中需要加密及解密的字段可添加該注解
2.聲明Base類,并實現encrypt和decrypt方法,方法實現利用java反射及自定義注解
3.所有需要用到加密及解密的實體對象,必須繼承自Base類
4.實體類加密時調用encrypt方法,解密時調用decrypt方法,如此可實現對該對象中敏感數據的加密解密
三、敏感信息加密實現
1.先看效果
注釋很清楚,先給對象設置身份證號,然后執行自加密方法,返回自己的引用,打印出來加密后該對象的json字符串;執行自解密方法,返回自己的引用,打印出來解密后該對象的json字符串。
2.設計實現結構
1
2
3
4
5
6
7
8
9
10
11
12
|
crypt | |--annotation | |--DecryptFiled | |--EncryptFiled |--crypt | |--EncryptDecryptInterface |--domain | |--BaseInfo | |--SimpleDomain |--utils | |--MySqlUtils |
2.1先看看注解的實現
1
2
3
4
5
6
7
8
9
10
11
12
|
/** * Created by bright on 2017/2/22. * * @author : */ @Target (ElementType.FIELD) @Retention (RetentionPolicy.RUNTIME) public @interface EncryptFiled { String value() default "" ; } 自定義注解 |
兩個注解的實現一致,注解名稱不同而已,不再貼另外一個注解的代碼。
2.2定義自加密、自解密接口
Base類實現該接口中的自加密自解密方法
1
2
3
4
5
6
7
8
9
10
11
|
/** * Created by bright on 2017/2/22. * * @author : */ public interface EncryptDecryptInterface { public <T> T encryptSelf(); public <T> T decryptSelf(); } 自定義接口 |
2.3MysqlUtils的實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
/** * 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類的實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
/** * 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一個簡單的對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * 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來個調用
1
2
3
4
5
6
7
8
9
10
11
|
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 |
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!
原文鏈接:http://www.cnblogs.com/shizhanming/p/6555241.html