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

探究SpringWeb对于请求的处理过程

探究目的

在路径归一化被提出后,越来越多的未授权漏洞被爆出,而这些未授权多半跟spring自身对路由分发的处理机制有关。今天就来探究一下到底spring处理了什么导致了才导致鉴权被绕过这样严重的问题。

DispatcherServlet介绍

首先在分析spring对请求处理之前之前,首先需要了解DispatcherServlet,它是Spring MVC的核心,负责接收HTTP请求,并根据请求信息分发到相应的Controller进行处理。DispatcherServlet重要特性如下:

  • 前端控制器模式:在Spring MVC框架中,DispatcherServlet实现了前端控制器设计模式。这个模式的主要思想是提供一个中心点,所有的请求将先到达这个中心点,然后由它进行分发。这样可以帮助我们将请求处理流程中的公共逻辑集中处理,从而提高了代码的可维护性。

  • 请求分发:当DispatcherServlet接收到一个HTTP请求后,它会把请求分发给相应的处理器。这个分发的过程主要依赖HandlerMapping组件。HandlerMapping根据请求的URL找到对应的Controller。

  • 处理器适配:找到了正确的处理器之后,DispatcherServlet需要调用这个处理器的方法来处理请求。这个过程由HandlerAdapter负责。HandlerAdapter会调用处理器的适当方法,并将返回值包装成ModelAndView对象。

  • 视图解析:DispatcherServlet还负责将处理器返回的ModelAndView对象解析为实际的视图。这个过程由ViewResolver完成。视图解析器根据ModelAndView中的视图名和已配置的视图解析器来选择一个合适的视图。

Spring对于请求的处理顺序

在具体了解DispatcherServlet如何工作之前需要先了解java项目中各个组件对于url的处理顺序。

图片

看懂该图后,可以清晰地知道大多的路径归一化问题是因为鉴权的过滤器或者拦截器对于url的处理与spring最后对路由分发时的处理不一致,导致鉴权失败,从而可以未授权访问系统。下面就来看看springweb对url究竟是如何解析的

SpringWeb对于请求的处理过程

以springboot2.2x为例自己搭建一个springboot环境,创建好controller后在controller内部打断点。

在调用链中可以清晰地看到,spring对于url的分发确实是在filter之后,接下来

图片

从调用链可以看出在过完Filterchain链上所有的Filter后最后调用了DispatcherServlet的servlet方法。

这里牵扯到一个java的机制,(不想深入了解java的可以略过这段)首先servlet在ApplicationFilterChain.java的225行被反射赋值为DispatcherServlet对象。所以231行调用的是DispatcherServlet的service方法且传入的参数是ServletRequest,ServletResponse类型。但是在DispatcherServlet中并没有service方法,在DispatcherServlet的父类FrameworkServlet中也没有重写接收ServletRequest和ServletResponse的对象service方法,所以调用链到了上一级父类Httpservlet这个抽象类的service方法。Httpservlet中的service方法又调用了接收HttpServletRequest对象的service方法,该方法又被FrameworkServlet重写。故最后调用了FrameworkServlet中的service。完全符合上面的调用链顺序。这里比较绕,大家可以自己跟一下就明白了。网上有很多对于这里的介绍都是错误的,学安全嘛还是要刨根问底一下。源码如下

图片

图片

图片

接着可以看到FrameworkServlet的service方法中super调用了Httpservlet的service方法,值得注意的是在该方法中调用的doGet方法并不是Httpservlet的doGet方法,而是FrameworkServlet的doGet方法。

图片

图片

后面一直跟着调用链走,一直跟进到doDispatch方法。

在该方法中做了很多比较关键的处理。

首先处理了content-type为multipart的请求,后根据mappedHandler = getHandler(processedRequest);这行代码获取了已注册的handlerMappings。

图片

HandlerMapping是一个接口,负责将客户端的HTTP请求映射到对应的Controller。具体来说,它决定哪个Controller应该处理一个给定的请求。其中RequestMappingHandlerMapping用的最多,它支持@RequestMapping注解,并且通常与@Controller注解一起使用。

图片

所以具体处理的逻辑也就在getHandler方法中

图片

这段代码是从已注册的handlerMappings中获取一个HandlerExecutionChain对象,这个对象是对请求要执行的处理器以及其所有相关的拦截器的封装。跟进循环中的getHandler

图片

getHandlerInternal方法是将HTTP请求找到处理这个请求的Handler,然后将其包装到HandlerExecutionChain对象中,以便后续的处理流程。

到了这一步可以确定了,springweb对url的匹配是在getHandlerInternal之中,跟进getHandlerInternal看看其具体实现。

图片

看过路径归一化的师傅们应该到这里就很熟悉了,这个版本的函数叫getLookupPathForRequest,新版本叫initLookupPath。而这行代码也就是为了获得请求路径(通俗说就是我们请求的url)。看看他是怎么处理的

图片

很明显获取url的是 getRequestUri(request)

图片

跟入

图片

decodeAndCleanUriString这个函数可以说是大部分路径归一化问题的罪魁祸首,包括shiro 2020-1937也是因此而起。这三个函数我们挨个看看他到底干了什么

图片

removeSemicolonContentInternal主要做了两件事

1、移除所有的分号

2、移除分号后面直到下一个斜杠”/”之间的所有字符

图片

decodeRequestString函数是对url进行url解码,在这里也要强调一下,经常会看到有师傅用url编码进行鉴权绕过的情况也是由于此处的原因,在过滤器中其实并没有对编码过url进行处理,而到了spring分发路由的时候,却对他进行了解码从而绕过了认证。

顺便提一句,实战过程中可能会碰到Nginx的情况,Nginx也会对url进行一层解码。

图片

图片

getSanitizedPath把双/替换成单/

在此之中removeSemicolonContentInternal问题最大,由于前文处理的模型可以看到url先经过过滤器,如果过滤器中逻辑稍有不当,便有可能存在绕过鉴权的情况。

举个简单的例子

String requestUri =  request.getRequestURI();
If(requestUri.endsWith(“js”)){filterChain.doFilter(servletRequest, servletResponse);
}else{
return ;
}

这是一个常见的对静态文件不进行鉴权的过滤器,然而此时则可以通过/api/xxxxxx;js对该鉴权进行绕过。因为filter处理url时if是通过了if的逻辑,而到了spring的doDispatch中则由刚刚所述的处理,将其分发到了/api/xxxxxx正确对应的接口。

由此产生了很多鉴权问题,在filter之中对url处理稍有不慎变会导致该问题的产生。

再回到springweb对请求的处理,除了刚刚介绍的三个函数对请求的处理之外,还有个地方需要注意,在getLookupPathForRequest之中可以看到this.alwayUseFullPath。这个地方也是一个出现漏洞的点,在springboot2.3.0RELEASE之前spring是可以解析/api/a/../xxxx为/api/xxxx的,是因为this.alwayUseFullPath默认为false,而在springboot2.3.0RELEASE之后,this.alwayUseFullPath默认为true。将无法再解析/api/a/../xxxx,会直接认为该url是个路径,去匹配相应的controller。

图片

有始有终,刚刚只是解析获得了lookuppath也就是请求中的路径,之后再通过前文提到过的getHandlerInternal函数的lookupHandlerMethod对spring获取的url与controller中的url进行匹配。

放几张跟踪的图

图片

图片

图片

图片

图片

跟踪到最后还有个要注意的点,是关于后缀的匹配模式

图片

如果useSuffixPatternMatch为true,且spring配置文件中spring.mvc.pathmatch.use-suffix-pattern的值也为true(我的环境是springweb5.2图中为false)

图片

环境版本高,但是想实验的师傅可以自己配置一下

图片

Spring这时能解析/path/path.js

图片

在1.x版本的springboot和4.x版本的springweb中存在该情况。

该情况也会绕过很多鉴权过滤器,使过滤器误以为用户请求的是静态资源。

总结

常出现漏洞的点

1、removeSemicolonContentInternal函数对分号进行了相关处理导致绕过过滤器鉴权

2、decodeRequestString对url进行解码,此处也可能存在问题

3、在springboot2.3.0RELEASE之前alwayUseFullPath默认值为false,所以可能会导致"../","..;/"绕过鉴权的情况

4、springboot 1.x版本可以解析/path/path.js这类带有后缀的请求,可能造成鉴权绕过

参考链接

https://github.com/spring-projects/spring-framework/

https://forum.butian.net/share/2214

相关文章:

探究SpringWeb对于请求的处理过程

探究目的 在路径归一化被提出后,越来越多的未授权漏洞被爆出,而这些未授权多半跟spring自身对路由分发的处理机制有关。今天就来探究一下到底spring处理了什么导致了才导致鉴权被绕过这样严重的问题。 DispatcherServlet介绍 首先在分析spring对请求处…...

如何使用Google Compute Engine入门指南快速创建和配置您的云虚拟机实例

文章目录 步骤1:创建 Google Cloud Platform(GCP)账户步骤2:设置 GCP 项目步骤3:启用 Google Compute Engine API步骤4:安装 Google Cloud SDK步骤5:创建虚拟机实例步骤6:连接到虚拟…...

springMVC中全局异常处理

前言: 当不同方法执行时,抛出相同异常。为了简约代码和避免重复使用try{}catch{}。此时使用统一异常处理。但局部的统一异常处理只能为所在类所调用。因此产生全局异常处理,该类中统一异常处理方法可以作用于整个controller。(以…...

【Nginx24】Nginx学习:压缩模块Gzip

Nginx学习:压缩模块Gzip 又是一个非常常见的模块,Gzip 现在也是事实上的 Web 应用压缩标准了。随便打开一个网站,在请求的响应头中都会看到 Content-Encoding: gzip 这样的内容,这就表明当前这个请求的页面或资源使用了 Gzip 压缩…...

我的私人笔记(zookeeper分布式安装)

分布式安装 1.安装前准备 (1)下载zookeeper:Index of /dist/zookeeper(当前使用为3.4.10版本) (2)安装JDK (3)拷贝zookeeper安装包到Linux系统下 (4)解压到指定目录 tar -xzvf zookeeper-3.4.10.tar.gz -C /opt/servers/ (5)修改名称 …...

小程序排名优化全攻略

随着小程序的快速发展,小程序之间的竞争也日益激烈。如何在竞争对手众多的环境下脱颖而出,通过小程序排名优化来提高曝光率和流量转化率,已成为许多小程序开发者和运营者关注的重点。本文将全面解析小程序排名优化的方法,让您可以更好地提升小程序的搜索排名。 【名即微】 小程…...

MySQL MHA

什么是 MHA MHA(Master High Availability)是一套优秀的MySQL高可用环境下故障切换和主从复制的软件 MHA 的出现就是解决MySQL 单点故障的问题 MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作 MHA能在故障切换的过程中最大程度上…...

Java API速记手册(持续更新ing...)

诸神缄默不语-个人CSDN博文目录 之所以干这个事原因也很简单,因为我3年没写Java了,现在在复健。 因为我最近都在用Python,所以跟Python一样的部分我就不写了。 最基本的框架public class MainClass {public static void main(String[] args…...

FANUC机器人电气控制柜内部硬件电路和模块详细介绍

FANUC机器人电气控制柜内部硬件电路和模块详细介绍 PSU电源单元 通过背板传输了如下电源 +5 +2.0V +3.3 +24v +24E +15V -15V 主板--接口描述: 主板内部结构: 面板电路板: 引申一下 KM21 与 KM22 的作用它们分别接至操作面板上上的急停按...

LGFormer:LOCAL TO GLOBAL TRANSFORMER FOR VIDEO BASED 3D HUMAN POSE ESTIMATION

基于视频的三维人体姿态估计的局部到全局Transformer 作者:马海峰 *,陆克 * †,薛健 *,牛泽海 *,高鹏程† * 中国科学院大学工程学院,北京100049 鹏程实验室,深圳518055 来源:202…...

数据结构零基础入门篇(C语言实现)

前言:数据结构属于C学习中较难的一部分,对应学习者的要求较高,如基础不扎实,建议着重学习C语言中的指针和结构体,万丈高楼平地起。 目录: 一,链表 1)单链表的大致结构实现 2&…...

Hugging News #0904: 登陆 AWS Marketplace

每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…...

Redis Redis的数据结构 - 通用命令 - String类型命令 - Hash类型命令

目录 Redis的数据结构: Redis命令: 通用命令:(通用指令是部分数据类型的,都可以使用的指令) KEYS查询命令: DEL删除命令: EXISTS判断命令: EXPIPE有效期设置命令&…...

vue中的几种name属性

vue中的几种name属性 组件名name name选项 export default{name:xxx } // 获取组件的name属性 this.$options.namevue-devtools调试工具里显示的组件名称; 未配置name选项,就是组件的文件名; vue3配置name通过defineOptions()函数 de…...

论文《面向大规模日志数据分析的自动化日志解析》翻译

论文《Towards Automated Log Parsing for Large-Scale Log Data Analysis》翻译 面向大规模日志数据分析的自动化日志解析翻译...

element-ui dialog弹窗 设置点击空白处不关闭

根据官网提供方法 场景:vue实现的网站有两个弹窗同时出现时,关闭报警,批量进度条弹窗也关闭了, 1、每一个页面都有可能出现的报警弹窗, 2、页面a批量操控硬件添加操作的进度条弹窗 开始以为是因为点击报警弹窗&#…...

第16节-PhotoShop基础课程-修复工具组-去水印

文章目录 前言1.污点修复画笔1.功能原理2.调整1.调整大小 Alt 右键 左右2.调整软硬 Alt 右键 上下 2.修复画笔工具 Alt 选取源1.常规2.选择图案 3.修补工具1.类型1.源2.目标 2.扩展 4.内容感知移动工具5.红眼工具 前言 去水印等 1.污点修复画笔 比如把下面的土豆&#xff08…...

conda的使用教程

conda的介绍 简单来说,conda软件就是来管理包的软件。以Python为例,在实际生活中,我们要处理多个不同的项目,因此,要安装不同的项目所需要的包,为了管理方便,conda就是用来打理不同项目的包&…...

客户端发现pod并与之通信

客户端发现pod并与之通信 pod需要一种寻找其他pod的方法来使用其他pod提供的服务,不像在没有Kubernetes的世界,系统管理员要在用户端配置文件中明确指出服务的精确IP地址 或者主机名来配置每个客户端应用,但同样的方法在Kubernetes中不适用 …...

Powershell模拟实现Linux下的tree命令

Powershell模拟实现Linux下的tree命令 代码 环境: P o w e r s h e l l 7 Powershell\ 7 Powershell 7 function Get-Tree {param([string]$directory ".",[int]$d 1,[switch]$f)$absolutePath Resolve-Path -Relative $directoryWrite-Host $absol…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

C++ 基础特性深度解析

目录 引言 一、命名空间(namespace) C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用(reference)​ C 中的引用​ 与 C 语言的对比​ 四、inline(内联函数…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

大数据学习(132)-HIve数据分析

​​​​🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言&#x1f4…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...