Skip to main content

JavaEE代码审计-鉴权逻辑

·393 words·2 mins
IIIIIIIIIIII
Author
IIIIIIIIIIII
A little bit about you

JavaEE代码审计-鉴权逻辑
#

拦截器
	Interceptor是一种拦截器,也称之为拦截器链(Interceptor Chain),主要用于拦截请求、响应或处理过程中的某些事件,比如权限认证、日志记录、性能测试等。在 Java 中,Interceptor可以用来扩展框架,增加或修改某个方法的行为,或者对应用流程做些前置处理、后置处理、环绕处理等。

过滤器
	Filter被称为过滤器,过滤器实际上就是对Web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用filter技术,可以实现对所有Web资源的管理,例如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
不是在代码中 
他这是网站启动就开始了

好处:
	减少代码重复性:
	全局统一处理:
	提前拦截,提升性能:
				拦截器在请求到达业务代码(如 Controller、Service)之前就拦截非法请求(如未登录、参数格式错误),避免无效的业务处理,减少服务器资源消耗。
				
	
	推荐两个进行互补
	    通常建议 **“拦截器做全局通用校验,代码做业务专属校验”**,优势互补:

案例一:newbee-mall-
#

可以发现源码中这种过滤器的代码而且写了是admin字段的过滤

preHandle是固定的写法和dofilter一样不是自己定义的 优先查看代码
@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        String uri = request.getRequestURI();
        if (uri.startsWith("/admin") && null == request.getSession().getAttribute("loginUser")) {
            request.getSession().setAttribute("errorMsg", "请登陆");
            response.sendRedirect(request.getContextPath() + "/admin/login");
            return false;
        } else {
            request.getSession().removeAttribute("errorMsg");
            return true;
        }
    }
    
    

1

  • preHandle:请求处理之前执行(如登录校验、权限判断);
  • postHandle:请求处理之后、视图渲染之前执行(如修改模型数据、添加全局参数);
  • afterCompletion:整个请求完成后执行(如资源清理、日志记录)。

绕过方法

/;/admin或//admin

1

//admin 匹配就为空了就饶过了逻辑 但是又正常解析admin界面

/;/admin 分号 ; 在 URI 中是 “路径参数分隔符”(RFC 规范),服务器会忽略分号及后续内容(或仅作为参数处理),因此 /;/admin 会被规范化为 /admin,实际访问的是 /admin 资源

案例二:medicine-mangement系统
#

yiyaoguanlixitong/admin/dist/index.html#/login

代码说明了

有这三个开头则放行
/dictionary/page
/file/upload
/yonghu/register
IgnoreAuth 带有这个的直接放行 比如  访问Login不需要鉴权
   @IgnoreAuth
    @RequestMapping(value = "/login")
    public R login(String username, String password, String captcha, HttpServletRequest request) {
        YuangongEntity yuangong = yuangongService.selectOne(new EntityWrapper<YuangongEntity>().eq("username", username));
        if(yuangong==null || !yuangong.getPassword().equals(password))
            return R.error("账号或密码不正确");
@Override

   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


       String servletPath = request.getServletPath();
       if("/dictionary/page".equals(request.getServletPath())  || "/file/upload".equals(request.getServletPath()) || "/yonghu/register".equals(request.getServletPath()) ){//请求路径是字典表或者文件上传 直接放行
           return true;
       }
       //支持跨域请求
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
       response.setHeader("Access-Control-Max-Age", "3600");
       response.setHeader("Access-Control-Allow-Credentials", "true");
       response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
       response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

       IgnoreAuth annotation;
       if (handler instanceof HandlerMethod) {
           annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
       } else {
           return true;
       }

       //从header中获取token
       String token = request.getHeader(LOGIN_TOKEN_KEY);
       
       /**
        * 不需要验证权限的方法直接放过
        */
       if(annotation!=null) {
        return true;
       }
       

http://192.168.56.1:8080/yiyaoguanlixitong/file/upload/../../admin/dist/index.html

比如我们找到了一个users下面的resetpass 因为它是带IgnoreAuth的 而且直接GET传入username直接越权

IgnoreAuth
@RequestMapping(value = "/resetPass")
   public R resetPass(String username, HttpServletRequest request){
    UsersEntity user = usersService.selectOne(new EntityWrapper<UsersEntity>().eq("username", username));
    if(user==null) {
       return R.error("账号不存在");
    }
    user.setPassword("123456");
       usersService.update(user,null);
       return R.ok("密码已重置为:123456");
   }

1

1

案例三:华夏ERP-过滤器
#

init是初始化不用看主要看DOFILTER

requestUrl != null && (requestUrl.contains("/login.html") || requestUrl.contains("/register.html

看这个如果有register.html就可以了那么我们直接构造跳过就行了

@Override
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
    HttpServletRequest servletRequest = (HttpServletRequest) request;
    HttpServletResponse servletResponse = (HttpServletResponse) response;
    String requestUrl = servletRequest.getRequestURI();
    //具体,比如:处理若用户未登录,则跳转到登录页
    Object userInfo = servletRequest.getSession().getAttribute("user");
    if(userInfo!=null) { //如果已登录,不阻止
        chain.doFilter(request, response);
        return;
    }
    if (requestUrl != null && (requestUrl.contains("/login.html") || requestUrl.contains("/register.html"))) {
        chain.doFilter(request, response);
        return;
    }
    if (verify(ignoredList, requestUrl)) {
        chain.doFilter(servletRequest, response);
        return;
    }
    if (null != allowUrls && allowUrls.length > 0) {
        for (String url : allowUrls) {
            if (requestUrl.startsWith(url)) {
                chain.doFilter(request, response);
                return;

/account/getAccount

浏览器不行换BP可以

1

同时他还判断请求JS CSS可以

 initParams = {@WebInitParam(name = "ignoredUrl", value = ".css#.js#.jpg#.png#.gif#.ico"),
                      @WebInitParam(name = "filterPath",
if (verify(ignoredList, requestUrl)) {
    chain.doFilter(servletRequest, response);
    return;
}

1

案例四:天猫-过滤器
#

直接../../绕过就行了

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest servletRequest = (HttpServletRequest) request;
    //如果是(登录界面,登录态失效界面),直接放行
    if(servletRequest.getRequestURI().contains("/admin/login") ||
            servletRequest.getRequestURI().contains("/admin/account")
    ){
        chain.doFilter(request, response);
    } else {
        logger.info("检查管理员权限");
        Object o = servletRequest.getSession().getAttribute("adminId");
        if(o == null){
            logger.info("无管理权限,返回管理员登陆页");
            request.getRequestDispatcher("/admin/login").forward(request, response);
        } else {
            logger.info("权限验证成功,管理员ID:{}",o);
            chain.doFilter(request, response);
        }
    }

1

Related

JavaEECC1链条持续更新+fastjson1.2.24+log4j
·1894 words·9 mins
JavaEE代码审计-文件操作
·773 words·4 mins
JavaEE代码审计-sql注入
·684 words·4 mins
NPS-内网攻防信息打点工具
·467 words·3 mins
PHP11-Laravel-代码审计
·305 words·2 mins