my batis 차단기 처리 민감 필드

76103 단어 my batis 학습 총화
my batis 차단 기 를 이용 하여 데이터베이스 민감 필드 를 복호화 합 니 다.
  • 서문
  • 사고방식 해석
  • 코드
  • 지나 간 구덩이 (칠판 두 드 리 기 포인트)
  • 엔 딩 멘 트
  • 머리말
    회사 의 업무 요구 로 인해 기 존 업무 에 영향 을 주지 않 고 데이터 베이스 에 있 는 민감 한 필드 를 암호 화하 고 복호화 해 야 합 니 다. 개인 솔 루 션 은 my batis 의 차단기 로 민감 한 필드 를 암호 화 해 야 합 니 다.
    사고의 방향 을 분석 하 다.
  • 암호 화 복호화 가 필요 한 entity 클래스 대상 과 그 중의 데이터
  • 를 주석 으로 표시 합 니 다.
  • my batis 는 Executor. class 대상 의 query, update 방법
  • 을 차단 합 니 다.
  • 방법 이 실행 되 기 전에 파 라 메 터 를 암호 화하 여 복호화 하고 차단기 가 실 행 된 후에 복호화 한 결과
  • 코드
    1. 차단기 설정 (interceptor 후 자신의 차단 기 를 위 한 패키지 경로)
    <plugins>
    		<plugin interceptor="com.github.miemiedev.mybatis.paginator.OffsetLimitInterceptor">
    			<property name="dialectClass" value="com.github.miemiedev.mybatis.paginator.dialect.OracleDialect" />
    		</plugin>
    		<plugin interceptor="com.XXX.XXXX.service.encryptinfo.DaoInterceptor" />
    	</plugins>
    

    2. 차단기 의 실현 에 특히 주의: Dao 방법 매개 변 수 는 단일 매개 변수, 다 중 매개 변수 map 형식, 그리고 enity 대상 매개 변수 유형 이 있 을 수 있 기 때문에 통 하지 않 는 유형 은 통 하지 않 는 처리 방식 (본 고 는 매개 변수 단일 문자열 과 enity 대상, 돌아 오 는 결과 집합 List > 와 enity) 이 다음 에 차단기 에 해당 하 는 스위치 를 추가 하여 매개 변수 암호 화 조회 여 부 를 제어 해 야 합 니 다.복호화 가 호 환 되 었 습 니 다.
    package com.ips.fpms.service.encryptinfo;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    import com.xxx.xxx.dao.WhiteListDao;
    import com.xxx.xxx.entity.db.WhiteListEntity;
    import com.xxx.xxx.service.util.SpringBeanUtils;
    import org.apache.ibatis.executor.Executor;
    import org.apache.ibatis.mapping.MappedStatement;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.plugin.Intercepts;
    import org.apache.ibatis.plugin.Invocation;
    import org.apache.ibatis.plugin.Plugin;
    import org.apache.ibatis.plugin.Signature;
    import org.apache.ibatis.session.ResultHandler;
    import org.apache.ibatis.session.RowBounds;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.xxx.xxx.annotation.EncryptField;
    import com.xxx.xxx.annotation.EncryptMethod;
    import com.xxx.xxx.common.utils.CloneUtil;
    import com.xxx.core.psfp.common.support.JsonUtils;
    import com.xxx.xxx.service.util.CryptPojoUtils;
    
    @Intercepts({
        @Signature(type=Executor.class,method="update",args={MappedStatement.class,Object.class}),
        @Signature(type=Executor.class,method="query",args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})
    })
    public class EncryptDaoInterceptor implements Interceptor{
    	private final Logger logger = LoggerFactory.getLogger(EncryptDaoInterceptor.class);
    	private WhiteListDao whiteListDao;
    	static int MAPPED_STATEMENT_INDEX = 0;
    	static int PARAMETER_INDEX = 1;
    	static int ROWBOUNDS_INDEX = 2;
    	static int RESULT_HANDLER_INDEX = 3;
    	static String ENCRYPTFIELD = "1";
    	static String DECRYPTFIELD = "2";
    	private static final String ENCRYPT_KEY = "encry146local";
    	private static final String ENCRYPT_NUM = "146";
    	private static boolean ENCRYPT_SWTICH = true;
    	/**
    	 *         
    	 * @return 1 true      0 false    
    	 */
    	private boolean getFuncSwitch(){
    		if(whiteListDao == null){
    			whiteListDao = SpringBeanUtils.getBean("whiteListDao",WhiteListDao.class);
    		}
    		try{
    			WhiteListEntity entity = whiteListDao.selectOne(ENCRYPT_KEY,ENCRYPT_NUM);
    			if(entity!=null && "1".equals(entity.getFlag())){
    				ENCRYPT_SWTICH = true;
    			}else{
    				ENCRYPT_SWTICH = false;
    			}
    		}catch (Exception e){
    			logger.error(this.getClass().getName()+".getFuncSwitch        ,          []:",e.getStackTrace());
    			return false;
    		}
    
    		return ENCRYPT_SWTICH;
    	}
    
    	/**
    	 *                
    	 * @param statementid
    	 * @return true    false    
    	 */
    	private boolean isWhiteList(String statementid){
    		boolean result = false;
    		String whiteStatementid = "com.ips.fpms.dao.WhiteListDao.selectOne";
    		if(whiteStatementid.indexOf(statementid)!=-1){
    			result = true;
    		}
    		return result;
    	}
    	@Override
    	public Object intercept(Invocation invocation) throws Throwable {
    		logger.info("EncryptDaoInterceptor.intercept    ==> ");
    		MappedStatement statement = (MappedStatement) invocation.getArgs()[MAPPED_STATEMENT_INDEX];
    		Object parameter = invocation.getArgs()[PARAMETER_INDEX];
    		logger.info(statement.getId()+"      :"+JsonUtils.object2jsonString(CloneUtil.deepClone(parameter)));
    		/*
    		 *
    		 *                     ,
    		 *         ,                   
    		 *
    		 *  */
    		if(!isWhiteList(statement.getId()) && getFuncSwitch()){
    			parameter = encryptParam(parameter, invocation);
    			logger.info(statement.getId()+"     :"+JsonUtils.object2jsonString(CloneUtil.deepClone(parameter)));
    		}
    		invocation.getArgs()[PARAMETER_INDEX] = parameter;
    		Object returnValue = invocation.proceed();
    		logger.info(statement.getId()+"      :"+JsonUtils.object2jsonString(CloneUtil.deepClone(returnValue)));
    		returnValue = decryptReslut(returnValue, invocation);
    		logger.info(statement.getId()+"      :"+JsonUtils.object2jsonString(CloneUtil.deepClone(returnValue)));
    		logger.info("EncryptDaoInterceptor.intercept    ==> ");
    		return returnValue;
    	}
    	/**
    	 *      
    	 * @param @param returnValue
    	 * @param @param invocation
    	 * @param @return
    	 * @return Object
    	 * @throws 
    	 *
    	 */
    	public Object decryptReslut(Object returnValue,Invocation invocation){
    		MappedStatement statement = (MappedStatement) invocation.getArgs()[MAPPED_STATEMENT_INDEX];
    		if(returnValue!=null){
    	       	 if(returnValue instanceof ArrayList<?>){
    	       		 List<?> list = (ArrayList<?>) returnValue;
    	       		 List<Object> newList  = new ArrayList<Object>();
    	       		 if (1 <= list.size()){
    	       			 for(Object object:list){
    	       				 Object obj = CryptPojoUtils.decrypt(object);
    	       				 newList.add(obj);
    	       			 }
    	       			 returnValue = newList;
    	       		 }
    	       	 }else if(returnValue instanceof Map){
    	       		String[] fields = getEncryFieldList(statement,DECRYPTFIELD);
    	       		if(fields!=null){
    	       			returnValue = CryptPojoUtils.getDecryptMapValue(returnValue,fields);
    	       		}
    	       	 }else{
    	       		 returnValue = CryptPojoUtils.decrypt(returnValue);
    	       	 }
            }
    		return returnValue;
    	}
    	/***
    	 *              
    	 * @param @param parameter
    	 * @param @param invocation
    	 * @param @return
    	 * @return Object
    	 * @throws 
    	 *
    	 */
    	public Object encryptParam(Object parameter,Invocation invocation){
    		MappedStatement statement = (MappedStatement) invocation.getArgs()[MAPPED_STATEMENT_INDEX];
    		try {
    			if(parameter instanceof String){
    				if(isEncryptStr(statement)){
    					parameter = CryptPojoUtils.encryptStr(parameter);
    				}
    			}else if(parameter instanceof Map){
    				String[] fields = getEncryFieldList(statement,ENCRYPTFIELD);
    				if(fields!=null){
    					parameter = CryptPojoUtils.getEncryptMapValue(parameter,fields);
    				}
    			}else{
    				parameter = CryptPojoUtils.encrypt(parameter);
    			}
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    			logger.info("EncryptDaoInterceptor.encryptParam    ==> " + e.getMessage());
    		}
    		return parameter;
    	}
    	@Override
    	public Object plugin(Object target) {
    		return Plugin.wrap(target, this);
    	}
    
    	@Override
    	public void setProperties(Properties properties) {
    
    	}
    	/**
    	 *     map       
    	 * @param statement
    	 * @param type
    	 * @return List
    	 * @throws 
    	 *
    	 */
    	private String[] getEncryFieldList(MappedStatement statement,String type){
    		String[] strArry = null;
    		Method method = getDaoTargetMethod(statement);
    		Annotation annotation =method.getAnnotation(EncryptMethod.class);
    		if(annotation!=null){
    			if(type.equals(ENCRYPTFIELD)){
    				String encryString = ((EncryptMethod) annotation).encrypt();
    				if(!"".equals(encryString)){
    					strArry =encryString.split(",");
    				}
    			}else if(type.equals(DECRYPTFIELD)){
    				String encryString = ((EncryptMethod) annotation).decrypt();
    				if(!"".equals(encryString)){
    					strArry =encryString.split(",");
    				}
    			}else{
    				strArry = null;
    			}
    		}
    		return strArry;
    	}
    	/**
    	 *   Dao     
    	 * @param @return
    	 * @return Method
    	 * @throws 
    	 *
    	 */
    	private Method getDaoTargetMethod(MappedStatement mappedStatement){
    		Method method = null;
    		try {
    			String namespace = mappedStatement.getId();
    		    String className = namespace.substring(0,namespace.lastIndexOf("."));
    		    String methedName= namespace.substring(namespace.lastIndexOf(".") + 1,namespace.length());
    			Method[] ms = Class.forName(className).getMethods();
    			for(Method m : ms){
    		        if(m.getName().equals(methedName)){
    		        	method = m;
    		        	break;
    		        }
    			}
    		} catch (SecurityException e) {
    			e.printStackTrace();
    			logger.info("EncryptDaoInterceptor.getDaoTargetMethod    ==> " + e.getMessage());
    			return method;
    			
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    			logger.info("EncryptDaoInterceptor.getDaoTargetMethod    ==> " + e.getMessage());
    			return method;
    		}
    		return method;
    	}
    	/**
    	 *            
    	 * @param @param mappedStatement
    	 * @param @return
    	 * @return boolean
    	 * @throws 
    	 *
    	 */
    	private boolean isEncryptStr(MappedStatement mappedStatement) throws ClassNotFoundException{
    		boolean reslut = false;
    		try {
    				Method m = getDaoTargetMethod(mappedStatement);
    	        	m.setAccessible(true);
    	        	Annotation[][] parameterAnnotations = m.getParameterAnnotations();
    		        	 if (parameterAnnotations != null && parameterAnnotations.length > 0) { 
    		        		 for (Annotation[] parameterAnnotation : parameterAnnotations) {  
    		        	         for (Annotation annotation : parameterAnnotation) {  
    		        	          if (annotation instanceof EncryptField) {  
    		        	        	  reslut = true;
    		        	          }
    		        	      }
    		        	 }
    	        	 }
    		} catch (SecurityException e) {
    			e.printStackTrace();
    			logger.info("EncryptDaoInterceptor.isEncryptStr  :==> " + e.getMessage());
    			reslut = false;
    		}
    		return reslut;
    	}
    
    }
    
    
    

    2. 주해 의 entity 대상
    //          
    @EncryptDecryptClass
    public class MerDealInfoRequest extends PagingReqMsg {
    //    
    	@EncryptField
        @DecryptField
        private String cardNo;
    }
    

    3. dao 방법 중의 단일 매개 변수
    List<Dealer> selectDealerAndMercode(@EncryptField String idcardno);
    

    4. 포 장 된 도구 클래스 (EncryptDecryptUtil. decryptStrValue 복호화 방법 EncryptDecryptUtil. decryptStrValue 암호 화 방법)
    package com.xxx.xxx.service.util;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.pdfbox.Encrypt;
    import org.apache.poi.ss.formula.functions.T;
    
    import com.xxx.xxx.annotation.DecryptField;
    import com.xxx.xxx.annotation.EncryptDecryptClass;
    import com.xxx.xxx.annotation.EncryptField;
    import com.xxx.xxx.common.utils.EncryptDecryptUtil;
    
    public class CryptPojoUtils {
    	 /**
         *   t      
         * @param t
         * @param 
         * @return
         */
        public static <T> T encrypt(T t) {
        	if(isEncryptAndDecrypt(t)){
    	        Field[] declaredFields = t.getClass().getDeclaredFields();
    	        try {
    	            if (declaredFields != null && declaredFields.length > 0) {
    	                for (Field field : declaredFields) {
    	                    if (field.isAnnotationPresent(EncryptField.class) && field.getType().toString().endsWith("String")) {
    	                        field.setAccessible(true);
    	                        String fieldValue = (String) field.get(t);
    	                        if (StringUtils.isNotEmpty(fieldValue)) {
    	    	                    field.set(t, EncryptDecryptUtil.encryStrValue(fieldValue) );
    	                        }
    	                        field.setAccessible(false);
    	                    }
    	                }
    	            }
    	        } catch (IllegalAccessException e) {
    	            throw new RuntimeException(e);
    	        }
        	}
            return t;
        }
        /**
         *         
         *
         * @param @param t
         * @param @return
         * @return T
         * @throws 
         *
         */
        public static <T> T EncryptStr(T t){
        	if(t instanceof String){
        		t = (T) EncryptDecryptUtil.encryStrValue((String) t);
        	}
        	return t;
        }
        /**
         *         
         * @param t
         * @param 
         */
        public static <T> T decrypt(T t) {
        	if(isEncryptAndDecrypt(t)){
    	        Field[] declaredFields = t.getClass().getDeclaredFields();
    	        try {
    	            if (declaredFields != null && declaredFields.length > 0) {
    	                for (Field field : declaredFields) {
    	                    if (field.isAnnotationPresent(DecryptField.class) && field.getType().toString().endsWith("String")) {
    	                        field.setAccessible(true);
    	                        String fieldValue = (String)field.get(t);
    	                        if(StringUtils.isNotEmpty(fieldValue)) {
    	                            field.set(t, EncryptDecryptUtil.decryptStrValue(fieldValue));
    	                        }
    	                    }
    	                }
    	            }
    	        } catch (IllegalAccessException e) {
    	            throw new RuntimeException(e);
    	        }
            }
             return t;
        }
        /**
         *             
         * @param @param t
         * @param @return
         * @return Boolean
         * @throws 
         *
         */
        public static <T> Boolean isEncryptAndDecrypt(T t){
        	Boolean reslut = false;
        	if(t!=null){
        		Object object = t.getClass().getAnnotation(EncryptDecryptClass.class);
            	if(object != null){
            		reslut = true;
            	}
        	}
    		return reslut;
        }
    }
    
    

    건 너 간 구덩이.
    1. 상기 기능 을 실현 한 테스트 에서 select 조회 방법의 매개 변 수 는 암호 화 에 성공 한 후에 도 Executor 실행 기 실행 방법 매개 변 수 는 암호 화 되 지 않 은 매개 변수 로 각 분야 의 신 들 이 해결 하지 못 한 방향 을 찾 았 습 니 다. 마지막 으로 프로젝트 에서 오픈 소스 의 페이지 플러그 인 을 인 용 했 고 Offset Limit Interceptor 차단 기 는 매개 변 수 를 final 로 설정 한 것 을 발 견 했 습 니 다.사용자 정의 차단기 가 이 sql 인 자 를 수정 하지 못 했 습 니 다.
    해결 방법: 사용자 정의 차단기 가 이 차단기 에 놓 인 후 사용자 정의 차단기 가 먼저 실행 되면 됩 니 다.
    
    	    //        
    		
    			
    		
    		
    	
    
    public Object intercept(final Invocation invocation) throws Throwable {
            final Executor executor = (Executor) invocation.getTarget();
            final Object[] queryArgs = invocation.getArgs();
            final MappedStatement ms = (MappedStatement)queryArgs[MAPPED_STATEMENT_INDEX];
            //          final ,                 
            final Object parameter = queryArgs[PARAMETER_INDEX];
            final RowBounds rowBounds = (RowBounds)queryArgs[ROWBOUNDS_INDEX];
            final PageBounds pageBounds = new PageBounds(rowBounds);
    
            final int offset = pageBounds.getOffset();
            final int limit = pageBounds.getLimit();
            final int page = pageBounds.getPage();
            .....    ....
            }
    

    2. 데이터베이스 저장량 데이터 처 리 는 차단 기 를 추가 한 후에 반드시 데이터베이스 의 저장량 데 이 터 를 처리 해 야 합 니 다. 처리 하지 않 으 면 조회 매개 변 수 는 암호 화 되 었 지만 데 이 터 는 명문 이 므 로 조회 조건 이 일치 하지 않 을 수 있 습 니 다.
    엔 딩 멘 트
    개인 코드 가 예 쁜 사람의 링크 를 마구 붙인다 (https://www.cnblogs.com/liu-s/p/8000293.html) 참고 할 만하 다

    좋은 웹페이지 즐겨찾기