当前位置: 首页 > news >正文

东营网站建设培训学校aso优化推广公司

东营网站建设培训学校,aso优化推广公司,开发网站的基本原则,如何进行网站推广活动过程横向越权 横向越权一般发生在应用系统做了【认证】#xff0c;但没有做【鉴权】的情况下#xff0c;也是最常见的漏洞之一。 认证#xff1a;即识别是否有权限访问系统#xff1b;鉴权#xff1a;即识别在系统中的权限是什么#xff1b; 例如#xff1a; // 访问某… 横向越权 横向越权一般发生在应用系统做了【认证】但没有做【鉴权】的情况下也是最常见的漏洞之一。 认证即识别是否有权限访问系统鉴权即识别在系统中的权限是什么 例如 // 访问某数据查询接口,接口返回ID为123的数据信息POST : https://xxxx/iservice/queryInfo?detail_id123 请求接口时一般都会要求携带TOKEN无论是JWT还是RSA的至少不会是裸奔。这里的TOKEN就是【认证】信息接口通过TOKEN去判断当前用户是否有请求接口的权限。但如果接口中没有做【鉴权】则会发生横向越权用户通过修改detail_id的值就可以遍历DB中的所有记录。 解决的思路 建立数据权限常见的有【RBACrole based access control】, 基于角色的权限控制一般用户不被直接授予权限而是通过Role去获取权限。将数据的访问权限与角色绑定用户拥有什么角色才能看到什么数据这样即使遍历接口也只能查询到当前用户自己的数据ID加密如例子中的detail_id如果我们换成uuid或其他无规则的值也可以降低被遍历的可能性 建立完善的权限策略是控制越权最合适的方法但很多系统已经维护了很多年里面的功能很庞大往里面集成权限策略难度较大需要去定义角色梳理业务数据与角色的关系然后开发权限管理功能再挨个功能去添加鉴权这里提供ID加密的方式去处理横向越权。 目的 1、对原代码业务入侵小2、降低数据遍历风险3、投入人天小代码实现思路 通过全局拦截API入参与返回值对可遍历字段进行加解密。无需前端参与后端返回数据时对字段进行加密加密算法保存在后端前端使用加密字段进行后续业务处理后端接口入参接收时进行解密。 序号业务字段1业务字段2业务字段3行ID【非业务字段对用户不可见】1xxxxxxxxxwMul8LwP 》 实际值1232xxxxxxxxx3vRRDk6X 》 实际值1243xxxxxxxxxTbxJ3IAe 》 实际值125 用户选择查看序号1的行时请求后端返回详细数据接口如下 https://xxxx/iservice/queryInfo?detail_idwMul8LwP 此时如果要恶意遍历接口的话难度相对较高还可以将ID的加密强度提升来提供安全性。 代码实现 以下均基于JAVA语言springboot框架实现。通过反射在拦截中判断字段是否有加密或解密注解进行对应的加解密操作后流转。 自定义注解 /*** 字段解密* author lu*/ Target({ElementType.FIELD,ElementType.PARAMETER}) Retention(RetentionPolicy.RUNTIME) public interface Decrypt {}解密在接口入参中使用一般为RO对象或者是基础类型的参数所以作用域为FIELD或PARAMETER/*** 字段加密* author lu*/ Target({ElementType.FIELD}) Retention(RetentionPolicy.RUNTIME) public interface Encrypt {}加密在返回值VO中使用一般都为对象所以注解作用域为FIELD加密算法 加密强度自己选择这里以DES加密为例 /*** 加解密* author lu*/ Slf4j public class DesUtil {public static final String SECURITY_KEY IxDQ4e5bCEY;public static String encrypt(String info) {byte[] key new byte[0];try {key new BASE64Decoder().decodeBuffer(SECURITY_KEY);} catch (IOException e) {log.error(加密失败,e);}DES des SecureUtil.des(key);String encrypt des.encryptHex(info);return encrypt;}public static String decode(String encrypt) {byte[] key new byte[0];try {key new BASE64Decoder().decodeBuffer(SECURITY_KEY);} catch (IOException e) {log.error(解密失败,e);}DES des SecureUtil.des(key);return des.decryptStr(encrypt);} }接口返回值加密 responseBodyAdvice —— 响应体的统一处理器一般用来统一返回值使用。这里用于返回值字段加密。/*** 返回值字段加密* author lu*/ Slf4j RestControllerAdvice public class ResponseEncryptAdvice implements ResponseBodyAdvice {/** 此处如果返回false , 则不执行当前Advice的业务 */Overridepublic boolean supports(MethodParameter methodParameter, Class aClass) {return true;}/*** title 写返回值前执行** */Overridepublic Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {try {// 获取data类型Class clazz body.getClass();// 是否是集合boolean isCollectionType Collection.class.isAssignableFrom(clazz);if(isCollectionType){return encodeList(body);}else{return encode(body);}}catch (Exception e){log.error(请求后置处理异常,e);}return body;}/*** 递归加密*/private JSONObject encode(Object object) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {// 获取data类型Class clazz object.getClass();// 转成JSON处理字段加密后数据类型会变原类无法处理JSONObject jsonObject (JSONObject) JSONObject.toJSON(object);// 递归遍历类里及父类所有属性找到所有带加密注解的字段Field[] fields FieldsUtils.getClassAllFields(clazz);for (Field field : fields) {// 获取字段值field.setAccessible(true);Object val field.get(object);if(valnull){// 空值不处理continue;}// final 修饰的跳过避免出现递归死循环的问题例如PageInfoint modify field.getModifiers();if(Modifier.isFinal(modify)){continue;}// 字段类型Class valClass val.getClass();// 是否是集合boolean isCollectionType Collection.class.isAssignableFrom(valClass);// 是否是对象排除掉基础数据类型与包装类boolean isObject isJsonObject(val);// 如果是带加密注解的字段不管什么类型直接转String加密if(field.isAnnotationPresent(Encrypt.class)){// 字段加密jsonObject.put(field.getName(), DesUtil.encrypt(val.toString()));}// 如果是集合类型else if(isCollectionType){JSONArray jsonArray encodeList(val);jsonObject.put(field.getName(),jsonArray);}// 基础数据类型else if(!isObject){// 基础数据类型且没有注解直接放过continue;}// 如果是自定义的类则继续下沉找是否有加密字段else /*if (valClass.getPackage().getName().startsWith(com.lu.test))*/{jsonObject.put(field.getName(),encode(val));}/*// 其他接口带泛型的例如Ipage , PageInfoelse if(valClass.equals(IPage.class)){// 调用获取行数据的方法Method method valClass.getMethod(size);}else if(valClass.equals(PageInfo.class)){// 把PageInfo转成JSON处理JSONObject jsonObject (JSONObject) JSONObject.toJSON(object);// 调用获取行数据的方法Method method valClass.getMethod(getList);// 获取行数据Object rows method.invoke(val);}*/}return jsonObject;}/*** 集合* param object* return*/private JSONArray encodeList(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {// 以JSONARRAY存储JSONArray jsonArray new JSONArray();Class clazz object.getClass();// 遍历集合Method sizeMethod clazz.getMethod(size);// 调用List的size()方法获取元素数量int size (int)sizeMethod.invoke(object);// 获取元素Method toArrayMethod clazz.getMethod(toArray);Object[] elementArr (Object[]) toArrayMethod.invoke(object);for (int i 0; i size; i) {// 获取元素属性//Field listField clazz.getDeclaredField(elementData);// 设置访问权限//listField.setAccessible(true);// 获取元素Object element elementArr[i];// 丢进去递归jsonArray.add(encode(element));}return jsonArray;}/*** 判断是否是JSON字符串* param object* return*/private static boolean isJsonObject(Object object) {try {JSONObject jsonObject (JSONObject) JSONObject.toJSON(object);return true;} catch (Exception e) {return false;}} }适用于常见的返回值类型List ,Ipage , PageInfo, 以及自定义返回对象 。 接口入参解密 POST / JSON 入参的处理相对麻烦因为参数的位置contentType多样性./*** 入参解密* author lu*/ Slf4j RestControllerAdvice public class RequestJsonBodyDecryptAdvice implements RequestBodyAdvice {/** 此处如果返回false , 则不执行当前Advice的业务 */Overridepublic boolean supports(MethodParameter methodParameter, Type type, Class? extends HttpMessageConverter? aClass) {return true;}/*** title 读取参数前执行* description 在此做些编码 / 解密 / 封装参数为对象的操作** POST 请求 JSON格式入参会进入这里** */Overridepublic HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class? extends HttpMessageConverter? aClass) throws IOException {try{// 当前接口方法Method method methodParameter.getMethod();// 获取参数集合 RequestBody 只有一个参数Parameter[] parameters method.getParameters();if(ArrayUtils.isNotEmpty(parameters)){for (Parameter parameter : parameters) {if(parameter.isAnnotationPresent(RequestBody.class)){Class bodyType parameter.getType();return new DecryptHttpInputMessage(httpInputMessage,type,bodyType);}}}}catch (Exception e){log.error(请求参数解密失败,e);throw new BusinessException(请求参数错误);}return httpInputMessage;}/*** title 读取参数后执行* author Xingbz*/Overridepublic Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class? extends HttpMessageConverter? aClass) {return body;}/*** title 无请求参数时的处理*/Overridepublic Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class? extends HttpMessageConverter? aClass) {return body;}/*** 解密-使用解密后的数据构造新的读取流*/class DecryptHttpInputMessage implements HttpInputMessage {private HttpHeaders headers;private InputStream body;public DecryptHttpInputMessage(HttpInputMessage inputMessage, Type type,Class bodyType) throws Exception {// 转存请求头this.headers inputMessage.getHeaders();// 请求JSONString bodyStr StringUtils.defaultString(IOUtils.toString(inputMessage.getBody(), UTF-8));log.info(headers:{},body:{},headers,bodyStr);try {// 有些保存接口是LIST需要特殊处理if(bodyType.equals(List.class)){// 获取LIST的内部泛型类JSONArray jsonArray JSONObject.parseArray(bodyStr);JSONArray decryptArray new JSONArray();if (ObjectUtils.isEmpty(type)){this.body IOUtils.toInputStream(jsonArray.toJSONString(), UTF-8);return;}ParameterizedType parameterizedType (ParameterizedType) type;Type[] actualTypeArguments parameterizedType.getActualTypeArguments();Class? elementType (Class?) actualTypeArguments[0];for (Object o : jsonArray) {decryptArray.add(decode(JSONObject.parseObject(JSONObject.toJSONString(o)),elementType));}// 传递到接口this.body IOUtils.toInputStream(decryptArray.toJSONString(), UTF-8);}else {// 先转成JSON对象JSONObject jsonObject JSONObject.parseObject(bodyStr);// 解密JSONObject finObject decode(jsonObject, bodyType);// 传递到接口this.body IOUtils.toInputStream(finObject.toJSONString(), UTF-8);}} catch (Exception e) {log.error(加密参数【{}】解密失败{}, bodyStr, e.getMessage(), e);// 传递到接口this.body IOUtils.toInputStream(bodyStr, UTF-8);}}Overridepublic InputStream getBody() {return body;}Overridepublic HttpHeaders getHeaders() {return headers;}}/*** 递归解密*/private JSONObject decode(JSONObject jsonObject,Class type) throws IllegalAccessException, NoSuchMethodException, NoSuchFieldException {// 取对象里的属性SetString keys jsonObject.keySet();// 取接受入参里的所有属性Field[] fields FieldsUtils.getClassAllFields(type);// 匹配两者解密、字段类型转换for (Field field : fields) {field.setAccessible(true);// 字段名String fieldName field.getName();// 字段类型Class fieldType field.getType();// 如果JSON中没有则直接跳过if(!keys.contains(fieldName)){continue;}// 是否是集合boolean isCollectionType Collection.class.isAssignableFrom(fieldType);// 当前字段是否带有解密注解if(field.isAnnotationPresent(Decrypt.class)){// 需要解密,一定是要String类型String val jsonObject.getString(fieldName);// 解String finVal DesUtil.decode(val);// 判断原来是什么类型//log.info(fileType:{},fieldType);if(ClassUtils.isPrimitiveOrWrapper(fieldType)){// 基础数据类型 直接替换jsonObject.put(fieldName,finVal);}else if(fieldType.equals(List.class)){// LIST集合用array的接口换成LIST去接收jsonObject.put(fieldName,JSONObject.parseArray(finVal));}else{if(isJsonString(finVal)) {jsonObject.put(fieldName,JSONObject.parseObject(finVal));}else{// 还存在一些BigDecimal类似的无法被判断为基础数据类型回到这里jsonObject.put(fieldName,finVal);}}}else if(fieldType.getPackage().getName().startsWith(com.lu.test)){// 如果是com.lu.test这个根包下的自定义对象则递归向下找jsonObject.put(fieldName,decode(jsonObject.getJSONObject(fieldName),fieldType));}else if(isCollectionType){// 以JSONARRAY存储JSONArray jsonArray jsonObject.getJSONArray(fieldName);JSONArray decodeArray new JSONArray();// 获取LIST中的泛型集合Type listType field.getGenericType();ParameterizedType parameterizedType (ParameterizedType) listType;Type[] actualTypeArguments parameterizedType.getActualTypeArguments();Class? elementType (Class?) actualTypeArguments[0];// 遍历集合for (Object o : jsonArray) {// 获取元素属性decodeArray.add(decode(JSONObject.parseObject(JSON.toJSONString(o)),elementType));}jsonObject.put(field.getName(),decodeArray);}}return jsonObject;}/*** 判断是否是JSON字符串* param jsonString* return*/private static boolean isJsonString(String jsonString) {try {JSONObject.parseObject(jsonString);return true;} catch (Exception e) {return false;}} }接口入参解密 GET POST FORM-DATA | URL /*** 入参解密** author lu*/ Slf4j Component public class RequestParamDecryptAdvice implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {//部分get请求不会带Content-Type/*if (ObjectUtils.isEmpty(request.getContentType())){return true;}*/// application/json 直接放过if(ObjectUtils.isNotEmpty(request.getContentType()) request.getContentType().toLowerCase().contains(application/json)){return true;}if (ObjectUtils.isEmpty(request.getContentType())){log.warn(当前请求 contentType 为空!);}// 请求头里获取解密标识String flag request.getHeader(DecryptRequestWrapper.DECRYPT_FLAG);if (StringUtils.isEmpty(flag)) {// 生成包装类DecryptRequestWrapper decryptRequest new DecryptRequestWrapper(request);// 判断是否需要解密HandlerMethod handlerMethod (HandlerMethod) handler;Method method handlerMethod.getMethod();//获取参数名集合String[] parameterNames ParameterUtil.getParameterNames(method);// 获取参数集合Parameter[] parameters method.getParameters();if (ArrayUtils.isNotEmpty(parameters)) {try {// 遍历参数int i0;for (Parameter parameter : parameters) {// 获取参数类型Class paramterType parameter.getType();// 断参数是否是基本数据类型以及包装类 带有解密注解if (ClassUtils.isPrimitiveOrWrapper(paramterType) parameter.isAnnotationPresent(Decrypt.class)) {// 获取密文//JDK版本必须是1.8及以上//编译时候必须有编译选项javac -parameters打开默认是关闭的// 否则这里parameter.getName()拿不到真实的参数名字if (iparameters.length-1) {return true ;}String orginVal request.getParameter(parameterNames[i]);// 空值不处理if (StringUtils.isEmpty(orginVal)) {log.warn(形参{}未从入参中获取到值, parameterNames[i]);continue;}// 非空解密 覆盖decryptRequest.setParameter(parameterNames[i], DesUtil.decode(orginVal));}// 自动以RO处理else if (paramterType.getPackage().getName().startsWith(com.lu.test)) {// 获取所有字段Field[] fields paramterType.getDeclaredFields();// 是否带解密注解这里不递归不考虑RO里还玩嵌套的,不是JSON格式的应该不存在这种情况for (Field field : fields) {if (ClassUtils.isPrimitiveOrWrapper(field.getType()) field.isAnnotationPresent(Decrypt.class)) {// 获取密文String orginVal request.getParameter(field.getName());// 空值不处理if (StringUtils.isEmpty(orginVal)) {log.warn(形参{}未从入参中获取到值, field.getName());continue;}// 非空解密 覆盖decryptRequest.setParameter(field.getName(), DesUtil.decode(orginVal));}}}i;// 其他常见的 request/response对象这些都不处理}} catch (Exception e) {log.error(字段解密异常, e);}}String uri request.getRequestURI().replace(request.getContextPath(), );request.getRequestDispatcher(uri).forward(decryptRequest, response);return false;}// 已经解密的return true;}Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {} }HandlerInterceptor 需要结合WebMvcConfigurer才能生效/*** author lu*/ Configuration public class WebMvcConfig implements WebMvcConfigurer {AutowiredRequestParamDecryptAdvice requestParamDecryptAdvice;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(requestParamDecryptAdvice);} }反射参数获取工具 /*** 自 java8 开始可以通过反射得到方法的参数名不过这有个条件你必须手动在编译时开启-parameters 参数* 部署项目时不可能设置这种东西*/ public class ParameterUtil {/*** Spring自带的参数提取工具类*/private static final DefaultParameterNameDiscoverer discoverer new DefaultParameterNameDiscoverer();/*** 获取参数名** param method 方法* return 参数名*/Nullablepublic static String[] getParameterNames(Method method) {return discoverer.getParameterNames(method);}/*** 获取参数名** param ctor 构造函数* return 参数名*/Nullablepublic static String[] getParameterNames(Constructor? ctor) {return discoverer.getParameterNames(ctor);} }应用场景 // ResponseResult 为自定义的统一返回值PostMapping(/query1)public ResponseResultSupErpVo querySup(RequestBody SupErpRo ro) {return supService.querySup(ro);}// ResponseResult 为自定义的统一返回值// IPage 为分页插件返回值GetMapping(/query2)public ResponseResultIPageSupErpVo querySup(RequestParam Decrypt Long headId) {return supService.querySup(headId);}Datapublic class SupErpVo {// 可遍历字段加密Encryptprivate Long id;private String supName;private String supDep;}Datapublic class SupErpRo {// 加密字段解密Decryptprivate Long id;private String supName;}
http://www.pierceye.com/news/192441/

相关文章:

  • 江苏宜兴做网站的电话seo基础培训
  • 企业手机端网站模板下载济南公司建站模板
  • 一般公司做网站多少钱南昌市房产网
  • 惠州网站小程序建设做公司永久免费网站什么好
  • 湖南涟钢建设有限公司网站局网站建设工作总结
  • 家乡ppt模板免费下载网站合肥百姓网网站建设
  • 免费整套ppt模板下载网站东莞建设教育网站
  • 漯河网站建设漯河ps制作个人网站首页
  • 电商网站公司软件开发和软件研发
  • 网站建设浙江公司网站开发运营新人要注意什么
  • 外贸网站模板哪里下载家里电脑可以做网站服务器吗
  • 长沙门户网站北京设计网站的公司
  • 站长统计平面设计找工作难吗
  • seo建站公司推荐电商平台活动策划方案
  • 建设淘宝客网站.lc和ev手机对比平台
  • vue 做企业网站特产网站开发背景
  • 奉新网站制作dede视频网站源码
  • 做动画网站去哪采集建设网站需要的资金清单
  • 网站后台发邮件注册公司需要什么证件和手续
  • 炫酷特效网站万网虚拟主机免费空间
  • 公司网站模板最新怀远网站建设哪家好
  • 交互式网站定义如何网上找加工订单
  • 一个域名可以做几个网站吗南城网站建设公司
  • 宝安商城网站建设flash新手入门简单动画制作
  • 设置网站建设WordPress adsen
  • 网站与微信内容建设与运维总结建筑网络图
  • 网站模板文件不存在网站建设礻金手指下拉十二
  • 东莞浩智建设网站公司做百度推广员赚钱吗
  • qq网站推广代码昆明哪里做网站
  • 章丘营销型网站设计公司青岛网络优化排名