Commit 98654e0b by WeiCong

完善数据安全框架

parent a20df4c4
...@@ -19,6 +19,8 @@ public class NoUiRequest { ...@@ -19,6 +19,8 @@ public class NoUiRequest {
private Map<String, ?> dataMap = new HashMap<String, Object>(); private Map<String, ?> dataMap = new HashMap<String, Object>();
private Map<String, ?> saveDisplayMap = new HashMap<String, Object>(); private Map<String, ?> saveDisplayMap = new HashMap<String, Object>();
private boolean isSecurity=false; private boolean isSecurity=false;
private String reqUrl;
private String trnName;
public NoUiRequest() { public NoUiRequest() {
...@@ -34,6 +36,15 @@ public class NoUiRequest { ...@@ -34,6 +36,15 @@ public class NoUiRequest {
this.userId = userId; this.userId = userId;
this.terminalType = terminalType; this.terminalType = terminalType;
this.mappingUrl = mappingUrl; this.mappingUrl = mappingUrl;
String[] mappingArgs = mappingUrl.split("/");
if(mappingArgs.length>1){
this.trnName = mappingArgs[mappingArgs.length - 2];
if(request.getRequestURI().indexOf(this.trnName)>0){
this.reqUrl=request.getRequestURI().substring(request.getRequestURI().indexOf(this.trnName)-1);
}else{
this.reqUrl=mappingUrl;
}
}
if(!StringUtil.isEmpty(security)){ if(!StringUtil.isEmpty(security)){
this.isSecurity=true; this.isSecurity=true;
} }
...@@ -125,4 +136,12 @@ public class NoUiRequest { ...@@ -125,4 +136,12 @@ public class NoUiRequest {
public boolean isSecurity() { public boolean isSecurity() {
return isSecurity; return isSecurity;
} }
public String getReqUrl() {
return reqUrl;
}
public String getTrnName() {
return trnName;
}
} }
...@@ -32,218 +32,216 @@ import java.util.HashMap; ...@@ -32,218 +32,216 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public abstract class AbstractCommonController { public abstract class AbstractCommonController {
protected static final Log log = LogFactory.getLog(AbstractCommonController.class); protected static final Log log = LogFactory.getLog(AbstractCommonController.class);
protected static String ON_CLICK = "ON_CLICK"; protected static String ON_CLICK = "ON_CLICK";
protected static String INIT = "INIT"; protected static String INIT = "INIT";
protected static String ON_CHANGE = "ON_CHANGE"; protected static String ON_CHANGE = "ON_CHANGE";
protected static String ON_CHECK = "ON_CHECK"; protected static String ON_CHECK = "ON_CHECK";
protected static String ON_STREAM_UPLOAD = "ON_STREAM_UPLOAD"; protected static String ON_STREAM_UPLOAD = "ON_STREAM_UPLOAD";
protected static String ON_STREAM_DOWNLOAD = "ON_STREAM_DOWNLOAD"; protected static String ON_STREAM_DOWNLOAD = "ON_STREAM_DOWNLOAD";
@Autowired @Autowired
private NoUiVersion noUiVersion; private NoUiVersion noUiVersion;
public String getMainPanel(){ public String getMainPanel() {
return ""; return "";
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Object event(String mappingUrl, String eventType, Map<String, Object> dataMap, MultipartFile file,HttpServletRequest request, HttpServletResponse response) { public Object event(String mappingUrl, String eventType, Map<String, Object> dataMap, MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
NoUiContext context = null; NoUiContext context = null;
Result ret = null; Result ret = null;
String serverEnc = null; String serverEnc = null;
try { try {
NoUiRequest noUiRequest = new NoUiRequest(request, mappingUrl, dataMap); NoUiRequest noUiRequest = new NoUiRequest(request, mappingUrl, dataMap);
Alias alias = new Alias(mappingUrl); Alias alias = new Alias(mappingUrl);
String trnName = alias.getTrnName(); String trnName = alias.getTrnName();
Map<String, ?> paramsMap = noUiRequest.getParamsMap(); Map<String, ?> paramsMap = noUiRequest.getParamsMap();
context = NoUiContextManager.createNoUiContext(noUiRequest); context = NoUiContextManager.createNoUiContext(noUiRequest);
// 交易参数赋值 // 交易参数赋值
for (String key : paramsMap.keySet()) { for (String key : paramsMap.keySet()) {
context.getSession().storeData(key, paramsMap.get(key)); context.getSession().storeData(key, paramsMap.get(key));
} }
// 设置old sysmod // 设置old sysmod
RedisLoginInfo redisLoginInfo = null; RedisLoginInfo redisLoginInfo = null;
if( !StringUtils.isEmpty(noUiRequest.getUserId()) ) //开放模式下 if (!StringUtils.isEmpty(noUiRequest.getUserId())) //开放模式下
redisLoginInfo = (RedisLoginInfo) RedisUtil.get(StringUtil.userUniqueId(noUiRequest)); redisLoginInfo = (RedisLoginInfo) RedisUtil.get(StringUtil.userUniqueId(noUiRequest));
if(redisLoginInfo != null) if (redisLoginInfo != null) {
{ NoUiPresentationUtil.setSysmod(context, (byte[]) redisLoginInfo.getSysmod());
NoUiPresentationUtil.setSysmod(context, (byte[]) redisLoginInfo.getSysmod()); context.setRedisLoginInfo(redisLoginInfo);
context.setRedisLoginInfo(redisLoginInfo); }
}
// 交易跳转
// 交易跳转 context.getSession().chain(true, trnName);
context.getSession().chain(true, trnName);
//执行可能存在的主面板的初始化
//执行可能存在的主面板的初始化 if (this.getMainPanel().length() > 0) {
if(this.getMainPanel().length() > 0) IPanel mainPanel = (IPanel) context.getSession().getBaseObject(null, this.getMainPanel());
{ mainPanel.invokeDefaultRules(context);
IPanel mainPanel = (IPanel)context.getSession().getBaseObject(null, this.getMainPanel()); }
mainPanel.invokeDefaultRules(context); // 模型赋值
} NoUiPresentationUtil.hanleInput(context, noUiRequest, alias);
// 模型赋值
NoUiPresentationUtil.hanleInput(context, noUiRequest, alias);
//数据安全性拦截-篡改数据拦截 //数据安全性拦截-篡改数据拦截
if(DataSecurityUtil.isSafeMode() && noUiRequest.isSecurity()){ if (DataSecurityUtil.isSafeMode() && noUiRequest.isSecurity()) {
if(paramsMap.containsKey(DataSecurityUtil.BACKGROUND_ID)){ if (DataSecurityUtil.needDecrypt(noUiRequest.getReqUrl())) {
String[] clientpars = DataSecurityUtil.getSafeConfigByTrnName(context,trnName); if (paramsMap.containsKey(DataSecurityUtil.BACKGROUND_ID)) {
if(!ArrayUtils.isEmpty(clientpars)){ String[] clientpars = DataSecurityUtil.getSafeConfigByReqUrl(context, noUiRequest.getReqUrl() + DataSecurityUtil.DECRYPT_FIX);
//合法性校验操作(场景:用户做修改、删除时调用) if (!ArrayUtils.isEmpty(clientpars)) {
serverEnc= (String) paramsMap.get(DataSecurityUtil.BACKGROUND_ID); //合法性校验操作(场景:用户做修改、删除时调用)
String errmsg=null; serverEnc = (String) paramsMap.get(DataSecurityUtil.BACKGROUND_ID);
if((errmsg=DataSecurityUtil.checkIllegalData(serverEnc,clientpars,noUiRequest.getUserId()))!=null){ String errmsg = null;
Result rt = new Result(ErrorCodes.ERROR, errmsg, null, noUiVersion.getVersion()); if ((errmsg = DataSecurityUtil.checkIllegalData(serverEnc, clientpars, noUiRequest.getUserId())) != null) {
return rt; Result rt = new Result(ErrorCodes.ERROR, errmsg, null, noUiVersion.getVersion());
return rt;
}
} }
} else {
Result rt = new Result(ErrorCodes.ERROR, DataSecurityUtil.ERROR_SERVERENC_NULL, null, noUiVersion.getVersion());
return rt;
} }
} }
} }
if (eventType.equals(ON_CLICK)) { if (eventType.equals(ON_CLICK)) {
IBaseObject dataField = baseObject(context, noUiRequest, alias); IBaseObject dataField = baseObject(context, noUiRequest, alias);
((IDatafield<?>) dataField).invokeEventRules(context, EventType.ON_CLICK, null); ((IDatafield<?>) dataField).invokeEventRules(context, EventType.ON_CLICK, null);
} else if (eventType.equals(ON_CHANGE)) { } else if (eventType.equals(ON_CHANGE)) {
IBaseObject dataField = baseObject(context, noUiRequest, alias); IBaseObject dataField = baseObject(context, noUiRequest, alias);
((IDatafield<?>) dataField).invokeEventRules(context, EventType.ON_CHANGE, null); ((IDatafield<?>) dataField).invokeEventRules(context, EventType.ON_CHANGE, null);
} else if (eventType.equals(ON_CHECK)) { } else if (eventType.equals(ON_CHECK)) {
for (String aliasKey : noUiRequest.getDataMap().keySet()) { for (String aliasKey : noUiRequest.getDataMap().keySet()) {
if (aliasKey.startsWith(Constants.MAPPING_PRE)) { if (aliasKey.startsWith(Constants.MAPPING_PRE)) {
continue; continue;
} }
String realPath = alias.getRelPath(aliasKey); String realPath = alias.getRelPath(aliasKey);
IBaseObject currentDataField = (IDatafield<?>) context.getSession().getBaseObject(context.getRoot(), realPath); IBaseObject currentDataField = (IDatafield<?>) context.getSession().getBaseObject(context.getRoot(), realPath);
if (currentDataField instanceof IDatafield<?>) { if (currentDataField instanceof IDatafield<?>) {
((IDatafield<?>) currentDataField).invokeCheckRules(context); ((IDatafield<?>) currentDataField).invokeCheckRules(context);
} }
} }
} else if (eventType.equals(ON_STREAM_UPLOAD) && file != null) { } else if (eventType.equals(ON_STREAM_UPLOAD) && file != null) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
IDatafield dataField = (IDatafield) baseObject(context, noUiRequest, alias); IDatafield dataField = (IDatafield) baseObject(context, noUiRequest, alias);
IStream stream = (IStream) dataField.getValue(); IStream stream = (IStream) dataField.getValue();
stream.setName(file.getOriginalFilename()); stream.setName(file.getOriginalFilename());
stream.setType(file.getContentType()); stream.setType(file.getContentType());
log.info("文件表单 key:" + file.getOriginalFilename() + ",size:" + file.getSize()); log.info("文件表单 key:" + file.getOriginalFilename() + ",size:" + file.getSize());
IOUtils.copy(file.getInputStream(), stream.getOutputStream(), 1024); IOUtils.copy(file.getInputStream(), stream.getOutputStream(), 1024);
dataField.invokeEventRules(context, EventType.ON_STREAM_UPLOAD, null); dataField.invokeEventRules(context, EventType.ON_STREAM_UPLOAD, null);
} else if (eventType.equals(ON_STREAM_DOWNLOAD)) { } else if (eventType.equals(ON_STREAM_DOWNLOAD)) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
IDatafield dataField = (IDatafield) baseObject(context, noUiRequest, alias); IDatafield dataField = (IDatafield) baseObject(context, noUiRequest, alias);
IStream stream = (IStream) dataField.getValue(); IStream stream = (IStream) dataField.getValue();
byte[] data = IOUtils.readFully(stream.getInputStream(), (int) stream.size()); byte[] data = IOUtils.readFully(stream.getInputStream(), (int) stream.size());
dataField.invokeEventRules(context, EventType.ON_STREAM_DOWNLOAD, null); dataField.invokeEventRules(context, EventType.ON_STREAM_DOWNLOAD, null);
IOUtils.write(data, response.getOutputStream()); IOUtils.write(data, response.getOutputStream());
} }
// 保存新的RedisLoginInfo // 保存新的RedisLoginInfo
if(redisLoginInfo!=null) //当为开放模式下,redisLoginInfo 为空 if (redisLoginInfo != null) //当为开放模式下,redisLoginInfo 为空
{ {
byte[] sysmodBytes = NoUiPresentationUtil.sysmodToBytes(context); byte[] sysmodBytes = NoUiPresentationUtil.sysmodToBytes(context);
redisLoginInfo.setSysmod(sysmodBytes); redisLoginInfo.setSysmod(sysmodBytes);
RedisUtil.set(StringUtil.userUniqueId(noUiRequest), redisLoginInfo); RedisUtil.set(StringUtil.userUniqueId(noUiRequest), redisLoginInfo);
} }
Map<String, Object> afterReturnData = handleReturnData(eventType, context, noUiRequest, alias); Map<String, Object> afterReturnData = handleReturnData(eventType, context, noUiRequest, alias);
//数据安全性拦截-篡改数据加密 //数据安全性拦截-篡改数据加密
if(DataSecurityUtil.isSafeMode() && noUiRequest.isSecurity()){ if (DataSecurityUtil.isSafeMode() && noUiRequest.isSecurity()) {
if(!paramsMap.containsKey(DataSecurityUtil.BACKGROUND_ID)){ if (DataSecurityUtil.needEncrypt(noUiRequest.getReqUrl())) {
//加密操作(场景:用户查询指定信息时调用,后续会做修改,删除等操作) //加密操作(场景:用户查询指定信息时调用,后续会做修改,删除等操作)
String[] pars = DataSecurityUtil.getSafeConfigByTrnName(context,trnName); String[] pars = DataSecurityUtil.getSafeConfigByReqUrl(context, noUiRequest.getReqUrl() + DataSecurityUtil.ENCRYPT_FIX);
if(!ArrayUtils.isEmpty(pars)){ serverEnc = DataSecurityUtil.encrypt(pars, noUiRequest.getUserId());
serverEnc=DataSecurityUtil.encrypt(pars,noUiRequest.getUserId()); afterReturnData.put(DataSecurityUtil.BACKGROUND_ID, serverEnc);
afterReturnData.put(DataSecurityUtil.BACKGROUND_ID,serverEnc);
}
} }
} }
ret = ResultUtil.result(NoUiPresentationUtil.retCode(context), NoUiPresentationUtil.retMsg(context), afterReturnData, ret = ResultUtil.result(NoUiPresentationUtil.retCode(context), NoUiPresentationUtil.retMsg(context), afterReturnData,
NoUiPresentationUtil.handleErrorReturnData(context, alias), NoUiPresentationUtil.handleCodeTableReturnData(context, alias), noUiVersion.getVersion()); NoUiPresentationUtil.handleErrorReturnData(context, alias), NoUiPresentationUtil.handleCodeTableReturnData(context, alias), noUiVersion.getVersion());
} catch (Exception e) { } catch (Exception e) {
log.error("OnClick command error", e); log.error("OnClick command error", e);
ret = ResultUtil.result(ErrorCodes.ERROR, "hander error", "service error", noUiVersion.getVersion()); ret = ResultUtil.result(ErrorCodes.ERROR, "hander error", "service error", noUiVersion.getVersion());
} finally { } finally {
if (context != null) if (context != null) {
{ //context.getSupport().disconnect();
//context.getSupport().disconnect(); context.dispose();
context.dispose(); }
} }
} return ret;
return ret;
}
}
private IBaseObject baseObject(NoUiContext context, NoUiRequest noUiRequest, Alias alias) {
private IBaseObject baseObject(NoUiContext context, NoUiRequest noUiRequest, Alias alias) { String aliasActionUrl = alias.getAliasActionUrl();
String aliasActionUrl = alias.getAliasActionUrl(); String actionUrl = alias.getRel().get(aliasActionUrl);
String actionUrl = alias.getRel().get(aliasActionUrl); IBaseObject baseObject = context.getSession().getBaseObject(context.getRoot(), actionUrl);
IBaseObject baseObject = context.getSession().getBaseObject(context.getRoot(), actionUrl); if (null == baseObject)
if (null == baseObject) throw new NoUiException("onClickUrl :" + actionUrl + " is not exsit");
throw new NoUiException("onClickUrl :" + actionUrl + " is not exsit"); return baseObject;
return baseObject; }
}
private Map<String, Object> handleReturnData(String eventType, NoUiContext context, NoUiRequest noUiRequest, Alias alias) {
private Map<String, Object> handleReturnData(String eventType, NoUiContext context, NoUiRequest noUiRequest, Alias alias) {
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> data = new HashMap<String, Object>(); // 初始化事件
// 初始化事件 if (eventType.equals(INIT)) {
if (eventType.equals(INIT)) { for (String aliasKey : alias.getRel().keySet()) {
for (String aliasKey : alias.getRel().keySet()) { if (aliasKey.startsWith(Constants.MAPPING_PRE)) {
if (aliasKey.startsWith(Constants.MAPPING_PRE)) { continue;
continue; }
} String realPath = alias.getRelPath(aliasKey);
String realPath = alias.getRelPath(aliasKey); IBaseObject baseObject = context.getSession().getBaseObject(context.getRoot(), realPath);
IBaseObject baseObject = context.getSession().getBaseObject(context.getRoot(), realPath);
data.put(aliasKey, NoUiPresentationUtil.handIBaseObject(context, baseObject, realPath));
data.put(aliasKey, NoUiPresentationUtil.handIBaseObject(context, baseObject, realPath)); }
} return data;
return data; }
}
NoUiPresentation gui = (NoUiPresentation) context.getGui();
NoUiPresentation gui = (NoUiPresentation) context.getGui(); Map<String, Object> modifyMap = gui.getModifyMap();
Map<String, Object> modifyMap = gui.getModifyMap(); List<String> containsKeys = new ArrayList<String>();
List<String> containsKeys = new ArrayList<String>(); for (Map.Entry<String, Object> modifyEntry : modifyMap.entrySet()) {
for (Map.Entry<String, Object> modifyEntry : modifyMap.entrySet()) { for (Map.Entry<String, String> aliasEntry : alias.getRel().entrySet()) {
for (Map.Entry<String, String> aliasEntry : alias.getRel().entrySet()) { String aliasKey = aliasEntry.getKey();
String aliasKey = aliasEntry.getKey(); String aliasPath = aliasEntry.getValue();
String aliasPath = aliasEntry.getValue(); if (aliasPath == null) {
if(aliasPath == null) log.error("错误的mapping:" + noUiRequest.getMappingUrl() + "--" + aliasKey + "--" + aliasPath);
{ continue;
log.error("错误的mapping:"+noUiRequest.getMappingUrl()+"--"+aliasKey+"--"+aliasPath); }
continue; if (modifyEntry.getKey() == null) {
} log.error("错误的modifymap:" + noUiRequest.getMappingUrl() + "--" + modifyMap);
if(modifyEntry.getKey() == null) continue;
{ }
log.error("错误的modifymap:"+noUiRequest.getMappingUrl()+"--"+modifyMap); if (aliasPath.startsWith(modifyEntry.getKey())) {
continue; Object val = modifyEntry.getValue();
} if (aliasKey == null)
if (aliasPath.startsWith(modifyEntry.getKey())) { continue;
Object val = modifyEntry.getValue(); data.put(aliasKey, NoUiPresentationUtil.handIBaseObject(context, val, aliasEntry.getValue()));
if(aliasKey == null) containsKeys.add(modifyEntry.getKey());
continue; }
data.put(aliasKey, NoUiPresentationUtil.handIBaseObject(context, val, aliasEntry.getValue()));
containsKeys.add(modifyEntry.getKey()); }
} }
} // 不能修改
} for (String key : modifyMap.keySet()) {
if (!containsKeys.contains(key)) {
// 不能修改 System.out.println("modify test:" + modifyMap.get(key).getClass());
for (String key : modifyMap.keySet()) { System.out.println("modify datafield:" + (modifyMap.get(key) instanceof IDatafield));
if (!containsKeys.contains(key)) { System.out.println("modify module:" + (modifyMap.get(key) instanceof IModule));
System.out.println("modify test:" + modifyMap.get(key).getClass()); System.out.println("modify moduleList:" + (modifyMap.get(key) instanceof IModuleList));
System.out.println("modify datafield:" + (modifyMap.get(key) instanceof IDatafield)); if (key == null)
System.out.println("modify module:" + (modifyMap.get(key) instanceof IModule)); continue;
System.out.println("modify moduleList:" + (modifyMap.get(key) instanceof IModuleList)); data.put(key, NoUiPresentationUtil.handIBaseObject(context, modifyMap.get(key), key));
if(key == null) }
continue; }
data.put(key, NoUiPresentationUtil.handIBaseObject(context, modifyMap.get(key), key));
} return data;
} }
return data;
}
} }
...@@ -6,6 +6,8 @@ import org.apache.commons.lang.ArrayUtils; ...@@ -6,6 +6,8 @@ import org.apache.commons.lang.ArrayUtils;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.sss.common.model.IBaseObject; import org.sss.common.model.IBaseObject;
import org.sss.common.model.IDatafield; import org.sss.common.model.IDatafield;
import org.sss.common.model.IModule;
import org.sss.common.model.IModuleList;
import org.sss.presentation.noui.common.Constants; import org.sss.presentation.noui.common.Constants;
import org.sss.presentation.noui.context.NoUiContext; import org.sss.presentation.noui.context.NoUiContext;
...@@ -16,72 +18,123 @@ import java.util.*; ...@@ -16,72 +18,123 @@ import java.util.*;
* 使用动态盐机制,每个盐只做一次双向校验后就失效 * 使用动态盐机制,每个盐只做一次双向校验后就失效
*/ */
public class DataSecurityUtil { public class DataSecurityUtil {
public static final String ENCRYPT_FIX = "_encode";
public static final String DECRYPT_FIX = "_decode";
public static final String ENCRYPT_ERROR = "encrypt exception"; public static final String ENCRYPT_ERROR = "encrypt exception";
public static final String DECRYPT_ERROR = "decrypt exception"; public static final String DECRYPT_ERROR = "decrypt exception";
public static final String BACKGROUND_ID="__bgid__"; public static final String BACKGROUND_ID = "__bgid__";
public static final String ERROR_SERVERENC_NULL="[服务端密文串异常],数据存在篡改风险!"; public static final String ERROR_SERVERENC_NULL = "[服务端密文串异常],数据存在篡改风险!";
public static final String ERROR_DYNAMICSALT_NULL="[获取的动态盐不存在],可能存在后台暴力破解风险,从而导致数据存在篡改被篡改的风险!"; public static final String ERROR_DYNAMICSALT_NULL = "[获取的动态盐不存在],可能存在后台暴力破解风险,从而导致数据存在篡改被篡改的风险!";
public static final String ERROR_DYNAMICSALT_EXCEPTION="[获取动态盐异常],可能redis异常,从而导致数据存在篡改被篡改的风险!"; public static final String ERROR_DYNAMICSALT_EXCEPTION = "[获取动态盐异常],可能redis异常,从而导致数据存在篡改被篡改的风险!";
public static final String ERROR_AES_DECODE="[服务端密文串解密失败],数据存在篡改风险!"; public static final String ERROR_AES_DECODE = "[服务端密文串解密失败],数据存在篡改风险!";
public static final String ERROR_NOTMATCH="[服务端密文串解密后的值与客户端密文串不同],数据存在篡改风险!"; public static final String ERROR_NOTMATCH = "[服务端密文串解密后的值与客户端密文串不同],数据存在篡改风险!";
public static final String SWITCH_KEY="switch";
public static final String SAFE_MODE="ON";
public static final String UNSAFE_MODE="OFF";
private static HashMap<String, String> securityConfig;
private static final Log log = LogFactory.getLog(DataSecurityUtil.class); private static final Log log = LogFactory.getLog(DataSecurityUtil.class);
public static boolean SWITCH = false;
private static HashMap<String, String[]> securityConfig = new HashMap<String, String[]>();
static{ static {
ClassPathResource resource = new ClassPathResource("security.properties",DataSecurityUtil.class); ClassPathResource resource = new ClassPathResource("security.properties", DataSecurityUtil.class);
try { try {
securityConfig= new HashMap<String, String>((Map) PropertyUtil.load("security.properties")); Map<String, String> tmp = new HashMap<String, String>((Map) PropertyUtil.load("security.properties"));
for (Map.Entry<String, String> entry : tmp.entrySet()) {
String key = entry.getKey();
String val = entry.getValue();
if ("switch".equals(key) && "ON".equals(val)) {
SWITCH = true;
} else {
//数据安全配置
if (securityConfig.containsKey(key)) {
log.warn("忽略重复的安全信息:" + key);
continue;
}
if (StringUtil.isEmpty(val)) {
log.warn("忽略值为空的安全信息:" + key);
continue;
}
securityConfig.put(key, val.split(";"));
}
}
} catch (Exception e) { } catch (Exception e) {
//降级处理 //降级处理
log.warn("加载安全配置文件失败:"+e.getMessage()); SWITCH = false;
securityConfig=new HashMap<String, String>(); securityConfig = new HashMap<String, String[]>();
securityConfig.put(SWITCH_KEY,UNSAFE_MODE); log.warn("加载安全配置文件失败:" + e.getMessage());
} }
} }
/** /**
* 是否开启安全模式,开启后会对前端传输的数据根据配置文件做篡改性校验 * 是否开启安全模式,开启后会对前端传输的数据根据配置文件做篡改性校验
*
* @return true表示开启;false不开启 * @return true表示开启;false不开启
*/ */
public static boolean isSafeMode(){ public static boolean isSafeMode() {
return SAFE_MODE.equalsIgnoreCase(securityConfig.get(SWITCH_KEY)); return SWITCH;
}
public static boolean needEncrypt(String reqUrl) {
return securityConfig.containsKey(reqUrl + ENCRYPT_FIX);
}
public static boolean needDecrypt(String reqUrl) {
return securityConfig.containsKey(reqUrl + DECRYPT_FIX);
} }
/** /**
* 获取指定交易的安全配置 * 获取指定交易的安全配置
* @param context 交易上下文 *
* @param trnName 交易名 * @param context 交易上下文
* @param configKey 安全配置的key
* @return 指定交易的安全配置信息 * @return 指定交易的安全配置信息
*/ */
public static String[] getSafeConfigByTrnName(NoUiContext context, String trnName){ public static String[] getSafeConfigByReqUrl(NoUiContext context, String configKey) {
String safeConfigByTrnName = securityConfig.get(trnName); String[] safeConfigByTrnNames = securityConfig.get(configKey);
if(!StringUtil.isEmpty(safeConfigByTrnName)){ for (String safeConfigByTrnName : safeConfigByTrnNames) {
String[] urls=safeConfigByTrnName.split(","); if (!StringUtil.isEmpty(safeConfigByTrnName)) {
String[] pars= new String[urls.length]; String[] urls = safeConfigByTrnName.split(",");
for(int i=0;i<urls.length;i++){ String[] pars = new String[urls.length];
String url=urls[i]; boolean flag = true;
IBaseObject baseObject =context.getSession().getBaseObject(context.getRoot(), url); for (int i = 0; i < urls.length; i++) {
if (null == baseObject) { String url = urls[i];
StringBuilder sb=new StringBuilder(); String lstTemplate=null;
sb.append("交易[").append(trnName).append("]对应的待校验字段["); if(url.indexOf("[]")>0){
sb.append(url).append("]在模型中未找到"); lstTemplate=url;
log.error(sb.toString()); url=url.substring(0,url.indexOf("[]"));
} else {
if (baseObject instanceof IDatafield<?>) {
IDatafield<Object> dataField = (IDatafield<Object>) baseObject;
pars[i]= dataField.getValue().toString();
}else{
StringBuilder sb=new StringBuilder();
sb.append("交易[").append(trnName).append("]对应的待校验字段[");
sb.append(url).append("]在模型中不是IDatafield类型");
log.error(sb.toString());
} }
IBaseObject baseObject = context.getSession().getBaseObject(context.getRoot(), url);
if (null == baseObject) {
flag = false;
break;
} else {
if (baseObject instanceof IDatafield<?>) {
IDatafield<Object> dataField = (IDatafield<Object>) baseObject;
String val = dataField.getValue().toString();
pars[i] = val;
} else if (baseObject instanceof IModuleList<?>) {
IModuleList<?> moduleList = (IModuleList<?>) baseObject;
String[] checkList=new String[moduleList.size()];
for (int index = 0; index < moduleList.size(); index++) {
IModule module = moduleList.get(index);
String npth=lstTemplate.replace("[]","["+index+"]");
IDatafield<Object> dataField = (IDatafield<Object>) context.getSession().getBaseObject(module, npth);
String val = dataField.getValue().toString();
checkList[index]=val;
}
pars[i]=String.join("_", checkList);
} else {
StringBuilder sb = new StringBuilder();
sb.append("安全配置[").append(configKey).append("]对应的待校验字段[");
sb.append(url).append("]在模型中不是IDatafield类型");
log.error(sb.toString());
}
}
}
if (flag) {
return pars;
} }
} }
return pars;
} }
return null; return null;
} }
...@@ -110,50 +163,66 @@ public class DataSecurityUtil { ...@@ -110,50 +163,66 @@ public class DataSecurityUtil {
/** /**
* 判断数据是否篡改 * 判断数据是否篡改
* *
* @param serverEnc 服务端产生的密文串 * @param serverEnc 服务端产生的密文串
* @param clientpars 客户端待校验参数 * @param clientpars 客户端待校验参数
* @param userId 用户id * @param userId 用户id
* @return 返回错误描述 * @return 返回错误描述
*/ */
public static String checkIllegalData(String serverEnc, String[] clientpars, String userId) { public static String checkIllegalData(String serverEnc, String[] clientpars, String userId) {
//1.判断服务端的密文串是否异常 //1.判断服务端的密文串是否异常
if(StringUtil.isEmpty(serverEnc) || ENCRYPT_ERROR.equals(serverEnc)){ if (StringUtil.isEmpty(serverEnc) || ENCRYPT_ERROR.equals(serverEnc)) {
log.warn(ERROR_SERVERENC_NULL); log.warn(ERROR_SERVERENC_NULL);
return ERROR_SERVERENC_NULL; return ERROR_SERVERENC_NULL;
} }
//2.用aes动态盐解密服务端密文串与客户端的密文串比对 //2.用aes动态盐解密服务端密文串与客户端的密文串比对
DynamicSalt dynamicSalt; DynamicSalt dynamicSalt;
try { try {
dynamicSalt=getDynamicSaltFromRedis(userId); dynamicSalt = getDynamicSaltFromRedis(userId);
if(dynamicSalt==null){ if (dynamicSalt == null) {
log.warn(ERROR_DYNAMICSALT_NULL); log.warn(ERROR_DYNAMICSALT_NULL);
return ERROR_DYNAMICSALT_NULL; return ERROR_DYNAMICSALT_NULL;
} }
} catch (Exception e) { } catch (Exception e) {
log.warn(ERROR_DYNAMICSALT_EXCEPTION+e.getMessage()); log.warn(ERROR_DYNAMICSALT_EXCEPTION + e.getMessage());
return ERROR_DYNAMICSALT_EXCEPTION; return ERROR_DYNAMICSALT_EXCEPTION;
} }
serverEnc=decrypt(serverEnc,dynamicSalt); serverEnc = decrypt(serverEnc, dynamicSalt);
if (StringUtil.isEmpty(serverEnc) || DECRYPT_ERROR.equals(serverEnc)) {
if(StringUtil.isEmpty(serverEnc) || DECRYPT_ERROR.equals(serverEnc)){
log.warn(ERROR_AES_DECODE); log.warn(ERROR_AES_DECODE);
return ERROR_AES_DECODE; return ERROR_AES_DECODE;
} }
String clientEnc=preHandle(clientpars); String clientEnc = preHandle(clientpars);
if(!serverEnc.equals(clientEnc)){ if(serverEnc.indexOf("_")>0){
//集合处理
String[] parts=serverEnc.split(",");
for(String part:parts){
if(!StringUtil.isEmpty(part)){
for(String item:part.split("_")){
if(item.equals(clientEnc)){
return null;
}
}
}
}
log.warn(ERROR_NOTMATCH); log.warn(ERROR_NOTMATCH);
return ERROR_NOTMATCH; return ERROR_NOTMATCH;
}else{
if (!serverEnc.equals(clientEnc)) {
log.warn(ERROR_NOTMATCH);
return ERROR_NOTMATCH;
}
} }
try { try {
RedisUtil.delete(getCacheSaltKey(userId)); RedisUtil.delete(getCacheSaltKey(userId));
} catch (Exception e) { } catch (Exception e) {
log.warn("删除失效盐出现异常:"+e.getMessage()); log.warn("删除失效盐出现异常:" + e.getMessage());
} }
return null; return null;
} }
/** /**
* 获取指定用户缓存盐的key * 获取指定用户缓存盐的key
*
* @param userId 用户ID * @param userId 用户ID
* @return 返回指定用户缓存盐的key * @return 返回指定用户缓存盐的key
*/ */
...@@ -167,32 +236,32 @@ public class DataSecurityUtil { ...@@ -167,32 +236,32 @@ public class DataSecurityUtil {
return content == null ? DECRYPT_ERROR : content; return content == null ? DECRYPT_ERROR : content;
} }
private static String preHandle(String[] pars){ private static String preHandle(String[] pars) {
if (ArrayUtils.isEmpty(pars)) { if (ArrayUtils.isEmpty(pars)) {
return null; return null;
} }
List<String> lst = Arrays.asList(pars); List<String> lst = Arrays.asList(pars);
String md5=String.join("", lst); String md5 = String.join(",", lst);
return md5; return md5;
} }
private static DynamicSalt getDynamicSaltFromRedis(String userId) throws Exception { private static DynamicSalt getDynamicSaltFromRedis(String userId) throws Exception {
String key=getCacheSaltKey(userId); String key = getCacheSaltKey(userId);
Object obj = RedisUtil.get(key); Object obj = RedisUtil.get(key);
DynamicSalt rs=parseDynamicSalt(obj); DynamicSalt rs = parseDynamicSalt(obj);
if(rs != null){ if (rs != null) {
return rs; return rs;
} }
return null; return null;
} }
private static DynamicSalt parseDynamicSalt(Object raw){ private static DynamicSalt parseDynamicSalt(Object raw) {
if(raw instanceof String){ if (raw instanceof String) {
String[] parts= ((String) raw).split("_"); String[] parts = ((String) raw).split("_");
if(parts != null && parts.length ==2){ if (parts != null && parts.length == 2) {
return new DynamicSalt(parts[0],parts[1]); return new DynamicSalt(parts[0], parts[1]);
} }
}else if(raw instanceof DynamicSalt){ } else if (raw instanceof DynamicSalt) {
return (DynamicSalt) raw; return (DynamicSalt) raw;
} }
return null; return null;
...@@ -222,7 +291,7 @@ public class DataSecurityUtil { ...@@ -222,7 +291,7 @@ public class DataSecurityUtil {
@Override @Override
public String toString() { public String toString() {
return iv+"_"+pwd; return iv + "_" + pwd;
} }
} }
} }
#安全开关(ON:开;OFF:关) #安全开关(ON:开;OFF:关)
switch=ON switch=ON
#客户管理——查询
/dblpty/sel_encode=\\ptyp\\ptylst[]\\inr
#客户管理——修改 #客户管理——修改
dbepty=\\ptygrp\\rec\\inr,\\ptygrp\\rec\\extkey /dbepty/init_decode=\\ptygrp\\rec\\inr
/dbepty/init_encode=\\ptygrp\\rec\\inr,\\ptygrp\\rec\\extkey
/dbepty/sav_decode=\\ptygrp\\rec\\inr,\\ptygrp\\rec\\extkey
#客户管理——删除 #客户管理——删除
dbdpty=\\ptygrp\\rec\\inr /dbdpty/init_decode=\\ptygrp\\rec\\inr
/dbdpty/init_encode=\\ptygrp\\rec\\inr
/dbdpty/sav_decode=\\ptygrp\\rec\\inr
# #
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment