文章目录

  • 安全功能
    • 审计模块参考
    • 审计模块实现
    • 使用TypeHandler实现数据的加解密转换

安全功能

安全审计要求:系统应提供覆盖所有用户的安全审计功能,对系统重要安全事件(包括用户和权限的增删改、配置定制、审计日志维护、用户登录和退出、越权访问、连接超时、密码重置、数据的备份和恢复等系统级事件,及业务数据增删改、业务流程定制、交易操作中断等业务级事件)进行审计

1.审计数据产生:

要求:系统审计记录表 日期、时间、事件类型、用户身份(用户名和IP地址,且应具有唯一性标识)、事件描述和事件结果

2.审计查阅:

要求:系统应提供对审计数据进行查询、排序、分类、分析统计的功能,按照行为主体、时间、事件类型等属性

3.异常事件告警:

要求:系统应对异常事件根据严重程度进行等级划分,当异常事件发生时依据安全策略采用弹出告警窗、声光报警、短信通知、邮件通知等方式进行告警;
异常事件包括连续登录失败、越权访问、IP地址异常等

4.审计事件存储:

i 要求:系统应提供对审计数据进行手动或自动备份的功能,自动备份需记录审计日志
ii 要求:系统应保证6个月内的审计记录无法被修改、删除和覆盖,6个月或更早之前的审计记录可依据安全策略进行覆盖
iii 要求:系统应可设置审计记录存储的容量上限,至少为1G,并在容量即将达到上限时应进行告警,弹出告警窗、声光报警、短信通知、邮件通知等方式

审计模块参考

参考:

https://www.cnblogs.com/samlin/archive/2010/02/08/log-operation-management.html

https://blog.csdn.net/t_jindao/article/details/85259145

https://blog.csdn.net/he90227/article/details/44175365

https://www.cnblogs.com/hooray/archive/2012/09/05/2672133.html

系统操作日志设计:

我们在做企业管理系统时,有多多少少都有对数据的完整性有所要求,比如要求系统不能物理删除记录,要求添加每一条数据时都要有系统记录、或者更新某条数据都需要跟踪到变化的内容、或者删除数据时需要记录谁删除了,何时删除了,以便误删后可以通过系统的XXX功能来恢复误删的数据。

为什么要做操作日志?

其实上文也描述了一些,其主要目的就是跟踪到每一个用户在系统的操作行为,如对数据进行查询、新增、编辑或删除甚至是登录等行为。更进一步的理解可以说是对用户使用系统情况的跟踪,对数据的跟踪防止数据意外删除、更改时有所记录,有所依据,以便对数据的还原,从某种程序上可以保护数据的完整性。

3.异步插入数据库日志记录

https://blog.csdn.net/hightrees/article/details/78765580

4.系统错误日志实现

https://blog.csdn.net/weixin_42456466/article/details/89672890

获取客户端ip地址

https://blog.csdn.net/u011521890/article/details/74990338

审计模块实现

  1. 自定义注解标记在handler方法上
@OperationLogger(name = "用户登录", table = OperationTable.USER, operationType = OperationType.SPEC)@OperationLogger(name = "退出登录", table = OperationTable.USER, operationType = OperationType.SPEC)@OperationLogger(name = "添加用户", table = OperationTable.USER, operationType = OperationType.ADD)@OperationLogger(name = "修改密码", table = OperationTable.USER, operationType = OperationType.UPDATE,idRef = 0)@OperationLogger(name = "批量添加用户", table = OperationTable.USER, operationType = OperationType.UPDATE)  @OperationLogger(name = "编辑用户信息", table = OperationTable.USER, operationType = OperationType.UPDATE,idRef = 0)@OperationLogger(name = "删除用户", table = OperationTable.USER, operationType = OperationType.DELETE,idRef = 0)@OperationLogger(name = "用户注册", table = OperationTable.USER, operationType = OperationType.SPEC)@OperationLogger(name = "忘记密码", table = OperationTable.USER, operationType = OperationType.SPEC)
@RestController
@RequestMapping("/user")
public class UserController{@Anonymous@RequestMapping("login.do")@OperationLogger(name = "用户登录", table = OperationTable.USER, operationType = OperationType.SPEC)public ResponseData login(){ResponseData responseData = new ResponseData<>();try {// todo 登录操作;if(/**登录成功*/){responseData.setStatus(ServiceResponseCodeEnum.SYS_SUCCESS.getCode());responseData.setMsg(ServiceResponseCodeEnum.SYS_SUCCESS.getMsg());         }else{responseData.setStatus(ServiceResponseCodeEnum.SYS_FAILED.getCode());responseData.setMsg(ServiceResponseCodeEnum.SYS_FAILED.getMsg());}}catch (Exception e) {responseData.setStatus(ServiceResponseCodeEnum.SYS_FAILED.getCode());responseData.setMsg(e.getMessage());}return responseData;}
}
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLogger {/** 操作业务名 */String name();/** 操作表名 */OperationTable table();/** 操作人 id */long operatorId() default 0L;/** 操作人名称 */String operatorName() default "";/** 不需要记录的字段 */String[] column() default {};/** 操作类型 操作类型(添加ADD,删除DELETE,修改UPDATE)*/OperationType operationType();String desc() default "";/** 0业务日志;1系统日志 */byte type() default 0;/** 异常事件严重程度 */byte level() default 1;/** 操作业务id */int idRef() default -1;/** 成功不记录,只记录失败操作*/boolean toLogger() default false;
}
public enum OperationType {SPEC((byte)0, "SPEC"),ADD((byte)1, "ADD"),DELETE((byte)2, "DELETE"),UPDATE((byte)3, "UPDATE"),private final Byte code;private final String type;OperationType(Byte code, String type) {this.code=code;this.type=type;}public Byte getCode() {return code;}public String getType() {return type;}
}
public enum OperationTable {USER(1L, "user"),DEVICE(2L, "device");private final Long id;private final String name;OperationTable(Long id, String name) {this.id=id;this.name=name;}public Long getId() {return id;}public String getName() {return name;}
}
  1. 自定义注解处理器
@Aspect
@Component
public class OperationLogAop {Logger logger = LoggerFactory.getLogger(OperationLogAop.class);@AutowiredILoggerService loggerService;//Controller层切点@Pointcut("@annotation(com.xyz.log.OperationLogger)")public void controllerAspect() {}@Around("controllerAspect()")public Object doAround(ProceedingJoinPoint joinPoint) {ResponseData result = null;try {// 记录操作日志...谁..在什么时间..做了什么事情..result = (ResponseData) joinPoint.proceed();// 在操作失败时候也记录操作人idLong id = 0L;if(result != null){if(result.getData() instanceof UserDetailVo){id = ((UserDetailVo) result.getData()).getId();} else if(result.getData() instanceof UserServiceBean){id = ((UserServiceBean) result.getData()).getId();}handleLog(joinPoint, result, id);}} catch (Throwable e) {// todo// 异常处理记录日志..log.error(e);}return result;}private void handleLog(JoinPoint joinPoint,ResponseData result,Long operatorId) {Map<String,Object> nameAndArgs = null;Long operationKey = null;String status = result.getStatus();try {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String ip = IpUtil.getIpAddr(request);//获取横切的方法名String methodName = joinPoint.getSignature().getName();//获取拦截的classString classType = joinPoint.getTarget().getClass().getName();//加载这个类Class<?> clazz = Class.forName(classType);//获取这个类上的方法名Method[] methods = clazz.getDeclaredMethods();// token中放了uid,在拦截器校验token时候setsetAttribute("uid", token中uid)String uid = (String) request.getAttribute("uid");uid = uid == null? "0":uid;for (Method method:methods){// 这个方法上面的注解是否含有自定义的注解// 并且方法名等于切点访问的方法名if (method.isAnnotationPresent(OperationLogger.class)&&method.getName().equals(methodName)){//获取method的注解OperationLogger operationLogger = method.getAnnotation(OperationLogger.class);HelmetOperationLogDto logDto = new HelmetOperationLogDto();//获取用户请求方法的参数并序列化为JSON格式字符串Object[] args = joinPoint.getArgs();if(null != args && args.length > 0) {//获取参数名称和值nameAndArgs = getParameMap(joinPoint);int idRef = operationLogger.idRef();if(idRef != -1){operationKey = (Long) args[idRef];}if(operationLogger.column().length != 0){for (String s : operationLogger.column()) {nameAndArgs.remove(s);}}}logDto.setName(operationLogger.name());logDto.setTableId(operationLogger.table().getId());logDto.setTableName(operationLogger.table().getName());logDto.setOperatorId(Long.valueOf(uid).equals(0L)?operatorId:Long.valueOf(uid));logDto.setOperationType(operationLogger.operationType().getCode());logDto.setOperationTime(new Date());logDto.setOperationIp(ip);logDto.setType(operationLogger.type());logDto.setNameAndArgs(nameAndArgs);logDto.setOperationKey(operationKey);logDto.setLevel(operationLogger.level());if(ServiceResponseCodeEnum.SYS_SUCCESS.getCode().equals(status)){logDto.setOperationDesc("操作成功");} else if(ServiceResponseCodeEnum.SYS_FAILED.getCode().equals(status)){logDto.setOperationDesc("操作失败");logDto.setLevel((byte)2);result.setData(null);} else if(ServiceResponseCodeEnum.PERMISSION_NOT_RIGHT.getCode().equals(status)){logDto.setOperationDesc("越权访问");logDto.setLevel((byte)3);result.setData(null);} else if(ServiceResponseCodeEnum.FAILED_LOGIN.getCode().equals(status)){logDto.setOperationDesc("登录失败");result.setData(null);result.setStatus(ServiceResponseCodeEnum.SYS_FAILED.getCode());} else if(ServiceResponseCodeEnum.FAILED_LOGIN_REPEATED.getCode().equals(status)){logDto.setOperationDesc("连续登录多次失败");logDto.setLevel((byte)3);result.setData(null);result.setStatus(ServiceResponseCodeEnum.SYS_FAILED.getCode());} else if(ServiceResponseCodeEnum.FAILED_LOGIN_LOCK.getCode().equals(status)){logDto.setOperationDesc("连续登录多次失败, 账号已经锁定");logDto.setLevel((byte)3);result.setData(null);result.setStatus(ServiceResponseCodeEnum.SYS_FAILED.getCode());}loggerService.addLog(logDto);}}} catch (Exception e) {logger.error("记录用户操作日志失败!", e);}}public Map<String, Object> getParameMap(JoinPoint joinPoint) {Map<String, Object> map = new HashMap<String, Object>();Object[] args = joinPoint.getArgs(); // 参数值String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames(); // 参数名for (int i = 0; i < argNames.length; i++) {if ("response".equals(argNames[i]) || "request".equals(argNames[i]) || "password".equals(argNames[i])) {continue;} else {map.put(argNames[i], args[i]);}}return map;}}

使用TypeHandler实现数据的加解密转换

https://www.cnblogs.com/wangjuns8/p/8688815.html

  1. 先自定义一个转化类,继承自BaseTypeHandler
public class AESEncryptHandler extends BaseTypeHandler{@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, AESUtil.encrypt((String)parameter));}@Overridepublic Object getNullableResult(ResultSet rs, String columnName) throws SQLException {String columnValue = rs.getString(columnName);return AESUtil.decrypt(columnValue);}@Overridepublic Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String columnValue = rs.getString(columnIndex);return AESUtil.decrypt(columnValue);}@Overridepublic Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String columnValue = cs.getString(columnIndex);return AESUtil.decrypt(columnValue);}
}

2)在resultMap上加引用,对应从数据库里取数据时转换成JAVA对象时的解密

–> 在mapper.xml里的对应字段上加上引用

<arg column="code" jdbcType="VARCHAR" javaType="java.lang.String" typeHandler="com.xyz.handler.AESEncryptHandler"/>
<arg column="user_phone" jdbcType="VARCHAR" javaType="java.lang.String" typeHandler="com.xyz.handler.AESEncryptHandler"/>
<resultMap id="UserByTaskResultMap" type="com.xyz.dto.user.UserByIdDto"><result property="id" column="id"/><result property="code" column="code" typeHandler="com.xyz.handler.AESEncryptHandler"/><result property="username" column="username"/><result property="num" column="num"/>
</resultMap>

所有涉及user表的code,user_phone字段都在这个mapper的resultMap映射关系中加上typeHandler,进行解密

3)在sql语句中加入引用,对应从JAVA对数据库传递数据的加密动作(所有用到敏感信息的地方都要加)

insert和update语句

<if test="code != null" >
#{code,jdbcType=VARCHAR,typeHandler=com.xyz.handler.AESEncryptHandler},
</if>
<if test="userPhone != null" >
#{userPhone,jdbcType=VARCHAR,typeHandler=com.xyz.handler.AESEncryptHandler},
</if>

安全测评之安全功能整改设计及代码相关推荐

  1. 安全测评之渗透测试整改设计和代码

    文章目录 安全测评之渗透测试 1. 任意文件上传漏洞 2. 中间件版本泄漏 3. 目录遍历 4. 关键会话重放攻击 5. 检测存在风险的无关服务和端口 6. 不安全的HTTP方法 安全测评之渗透测试 ...

  2. App中 微信分享 代付功能 业务设计 与 代码实现

    先上图 场景 本例的代付场景是,开发一款APP应用,APP中具有支付能力,按照微信 支付对接要求已经完成APP支付的对接.现在要玩点新花样,找人代付订 单.用户在APP中下单后选择找人代付,将分享H5 ...

  3. 学生综合测评系统(c++课程设计)

    目录 <实验课题> <系统分析与设计> <代码实现> (1) 类的编写 (2) 链表的使用 (3) 菜单目录的实现 <程序演示> <源码+开题报告 ...

  4. 功能测试用例设计方法有哪些?

    知识永远学不完,但多懂一点知识就会让生活更轻松一点! 一.什么是功能测试? ①顾名思义,功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到需求要求的功能. ②功能测试也叫 ...

  5. Atitit截屏功能的设计解决方案

    Atitit截屏功能的设计解决方案 自己实现.... 使用快捷键.. 弹出自己的win,,背景是屏幕快照 点击鼠标光标变成十字状态 出现截屏窗口 调整截屏窗口位置与大小 释放鼠标,三个btn,,  复 ...

  6. ASP.NET MVC:缓存功能的设计及问题

    ASP.NET MVC:缓存功能的设计及问题 这是非常详尽的asp.net mvc中的outputcache 的使用文章. [原文:陈希章 http://www.cnblogs.com/chenxiz ...

  7. axios取消功能的设计与实现

    取消功能的设计与实现 #需求分析 有些场景下,我们希望能主动取消请求,比如常见的搜索框案例,在用户输入过程中,搜索框的内容也在不断变化,正常情况每次变化我们都应该向服务端发送一次请求.但是当用户输入过 ...

  8. Java充电宝模型设计_继续探讨点赞功能模块设计

    继续探讨点赞功能模块设计 前几天我们设计了点赞模块的模块,大致思路就是: 用户点赞,首先缓存到redis中进行保存,redis中既要保存点赞总数,还要保存点赞记录.然后定时执行redis数据到数据库中 ...

  9. 界面设计方法(2)— 6.功能按钮设计(删除,保存,提交)

    接着上一篇功能按钮设计的说明,这一篇介绍功能按钮"删除.保存.提交"的三种形式.这三种形式是界面内容处理过程中的功能(删除.保存).界面处理完成时的功能(提交).同样分为基本功能和 ...

最新文章

  1. 【机器学习实战 第九章】树回归 CART算法的原理与实现 - python3
  2. http提交json格式数据自动加\
  3. ICA(独立成分分析)笔记
  4. 使用pip安装python库的几种方式,解决pip安装python库慢的问题
  5. 微信卡券 - 微信公众平台 整理笔记
  6. 小话设计模式四:策略模式
  7. 1499元!魅族Watch“天青”配色正式首销:与手机完全互联互通
  8. Spring实战基础1
  9. 2021数学建模B题详细思路
  10. Java基础每日一练—第5天:预测身高案列
  11. 使用nim master为oracle2分区安装os,使用 NIM 资源部署自定义的 AIX 系统
  12. qua数据统计缺失问题之终结
  13. 细致的网站开发流程有哪些呢?
  14. 手机照片误删怎么找回
  15. NR5G基础概念扫盲
  16. 反向传播神经网络(BPNN)的实现(Python,附源码及数据集)
  17. 关于解决移动端息屏后定时器不工作的问题
  18. 【调剂】浙江大学计算机学院机械专业2023年硕士研究生招生调剂通知
  19. Unity3D制作3D虚拟漫游场景(一)
  20. 基于机器学习技术的用户行为分析:当前模型和应用研究综述(A survey for user behavior analysis based on machine learning technique)

热门文章

  1. 滑动平均值滤波的VERILOG实现
  2. zzulioj -- 1261 : 小媛在努力
  3. 互联网时代内容分发四宗罪
  4. vue传值的几种方法
  5. 【计算机网络】LAN、WIFI与LTE
  6. vista系统重装下载安装教程
  7. 【滴滴出行】真题-地下迷宫
  8. Cloudera Manager搭建集群服务器启动失败
  9. 使用招商银行一卡通网上银行转账时 老提示 时间错误 或 网络错误:请求被重发
  10. 【DIY】宿舍简易磁石门吸(+3D文件)