my batis 차단기 처리 민감 필드
76103 단어 my batis 학습 총화
회사 의 업무 요구 로 인해 기 존 업무 에 영향 을 주지 않 고 데이터 베이스 에 있 는 민감 한 필드 를 암호 화하 고 복호화 해 야 합 니 다. 개인 솔 루 션 은 my batis 의 차단기 로 민감 한 필드 를 암호 화 해 야 합 니 다.
사고의 방향 을 분석 하 다.
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) 참고 할 만하 다