日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据安全之MySQL数据加解密的实现方案

發布時間:2024/3/13 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据安全之MySQL数据加解密的实现方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在我們日常的業務需求中,經常會遇到需要對存儲的用戶敏感數據進行加密處理的場景,如用戶的身份信息、住址、身份證號等等,本文我們就討論下,業務系統(后端)如何實現數據存儲(基于MySQL)的加解密功能。

技術棧:springboot、mybatis、mysql等

方案一:基于spring aop攔截mybatis mapper.

第一步:定義注解@Encrypt

@Target(ElementType.METHOD)//注解的范圍是類、接口、枚舉的方法上 @Retention(RetentionPolicy.RUNTIME)//被虛擬機保存,可用反射機制讀取 public @interface Encrypt{/*** 入參需要加密的字段* @return*/String[] paramFields() default {};/*** 響應參數需解密的字段* @return*/String[] respFields() default {}; }

第二步:開發攔截器處理類

@Slf4j @Aspect @Component public class EncryptAspect {@Pointcut("@annotation(com.xxx.annotation.Encrypt)")public void encryPointCut() {}@Around("encryPointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();final Sm4Intercept annotation = method.getAnnotation(Encrypt.class);if (null == annotation) {return joinPoint.proceed();}//加密入參對象屬性值encryptRequest(joinPoint, annotation);//執行目標方法Object response = joinPoint.proceed();//解密響應結果對象的屬性值decryptResponse(response, annotation);return response;}/*** 加密請求入參對象** @param joinPoint* @param annotation*/private void encryptRequest(ProceedingJoinPoint joinPoint, Sm4Intercept annotation) {//獲取接口的入參列表final Object[] params = joinPoint.getArgs();if (!CollectionUtil.isEmpty(params)) {//接口入參Object param = params[0];//接口入參對象的屬性列表Field[] fields = param.getClass().getDeclaredFields();if (!CollectionUtil.isEmpty(annotation.paramFields())) {//遍歷加密入參的屬性值Arrays.stream(annotation.paramFields()).forEach(target -> {Field field = Arrays.stream(fields).filter(f -> f.getName().equals(target)).findFirst().orElse(null);if (null != field) {//反射獲取目標屬性值Object fieldValue = getFieldValue(param, field.getName());if (null != fieldValue) {String encryFieldValue = EncryptUtil.encryptEcb(key, fieldValue.toString());log.info("類{}的屬性{}的值{}已被加密為{}", param.getClass().getName(), target, fieldValue, encryFieldValue);setFieldValue(param, field.getName(), encryFieldValue);}}});}}}/*** 解密響應結果對象的屬性值** @param object* @param annotation*/private void decryptResponse(Object object, Sm4Intercept annotation) {//返回結果是list時if (object instanceof List) {decryptListObject((List) object, annotation);return;}//返回結果為單對象時decryptObject(object, annotation);}/*** 解密list中對象的屬性值** @param list* @param annotation*/private void decryptListObject(List list, Sm4Intercept annotation) {list.stream().forEach(record -> decryptObject(record, annotation));}/*** 解密單對象的屬性值** @param record* @param annotation*/private void decryptObject(Object record, Sm4Intercept annotation) {//接口返回對象的屬性列表Field[] fields = record.getClass().getDeclaredFields();if (!CollectionUtil.isEmpty(annotation.respFields())) {//遍歷加密入參的屬性值Arrays.stream(annotation.respFields()).forEach(target -> {Field field = Arrays.stream(fields).filter(f -> f.getName().equals(target)).findFirst().orElse(null);if (null != field) {//反射獲取目標屬性值Object fieldValue = getFieldValue(record, field.getName());if (null != fieldValue) {String decryFieldValue = EncryptUtil.decryptEcb(key, fieldValue.toString());log.info("類{}的屬性{}的值{}已被解密為{}", record.getClass().getName(), target, fieldValue, decryFieldValue);setFieldValue(record, field.getName(), decryFieldValue);}}});}}/*** 通過反射,用屬性名稱獲得屬性值** @param thisClass 需要獲取屬性值的類* @param fieldName 該類的屬性名稱* @return*/private Object getFieldValue(Object thisClass, String fieldName) {Object value = new Object();try {Method method = thisClass.getClass().getMethod(getMethodName(fieldName, "get"));value = method.invoke(thisClass);} catch (Exception e) {}return value;}/*** 通過反射,設置屬性值** @param thisClass* @param fieldName* @param fieldValue*/private void setFieldValue(Object thisClass, String fieldName, Object fieldValue) {try {Method method = thisClass.getClass().getMethod(getMethodName(fieldName, "set"), String.class);method.invoke(thisClass, fieldValue);} catch (Exception e) {}}/*** 獲取方法名稱(getXXX,setXXX)** @param fieldName* @param methodPrefix* @return*/private String getMethodName(String fieldName, String methodPrefix) {return methodPrefix.concat(fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));} }

第三步:mapper中定義注解@Encrypt進行數據攔截

@Mapper public interface UserInfoMapper extends BaseMapper<UserInfo> {/*** 如果查詢條件中包含username,則在mapper執行前進行加密* 如果返回數據中包含username及address等信息,則進行解密 * @param vo* @return*/@Encrypt(paramFields = {"userName"}, respFields = {"userName", "address"})List<UserInfo> findUserInfo(UserSearchVo vo); }

這樣,便實現了在數據查詢(或更新、插入等)時,完成入參及返回數據的加解密操作。不過這種處理方式僅限于數據操作是通過Dao的mapper接口調用時,如果想處理更多場景,如通過mybatis-plus的Wraper方式進行數據處理時,則考慮用后面的第二種處理方式。

方案二:基于mybatis自帶的擴展插件(plugins)實現

MyBatis 允許你在映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

這些類中方法的細節可以通過查看每個方法的簽名來發現,或者直接查看 MyBatis 發行包中的源代碼。 如果你想做的不僅僅是監控方法的調用,那么你最好相當了解要重寫的方法的行為。 因為在試圖修改或重寫已有方法的行為時,很可能會破壞 MyBatis 的核心模塊。 這些都是更底層的類和方法,所以使用插件的時候要特別當心。

通過 MyBatis 提供的強大機制,使用插件是非常簡單的,只需實現 Interceptor 接口,并指定想要攔截的方法簽名即可。

?插件的使用參考實現如下(mybatis官方文檔)

@Slf4j @Component @Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class })}) public class ExamplePlugin implements Interceptor {private Properties properties = new Properties();public Object intercept(Invocation invocation) throws Throwable {// implement pre processing if needObject returnObject = invocation.proceed();// implement post processing if needreturn returnObject;}public void setProperties(Properties properties) {this.properties = properties;} }

即在mybatis的Executor的query方法執行前后進行攔截,如事先定義好需要加解密的“配置規則”(如“對哪個表的哪些字段需要加解密”、“方法的出入參需加解密的字段”等等),然后攔截sql的請求參數及執行的返回結果,對其進行相應的數據加解密操作

本文的核心實現思路都是圍繞spring aop進行實現的,足以說明aop思想的強大之處,大家平時學習工作中一定要勤學、多用、多練!希望本文可以幫助到有需要的朋友們!

總結

以上是生活随笔為你收集整理的数据安全之MySQL数据加解密的实现方案的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。