Commit 98654e0b by WeiCong

完善数据安全框架

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