有不为 發表於 2025-6-25 08:34:00

Spring Boot 使用 Tomcat 作为容器时访问根 context-path 302分析

<p>起因是安全团队反馈了一个漏洞,说通过公网域名访问内网中的一个SpringBoot服务的根路径,原本是域名的url变成了服务的内网的ip。</p>
<p>简略版的网络拓扑如下:<br>
<img src="https://img2024.cnblogs.com/blog/1407141/202504/1407141-20250411153832067-1592952718.png"></p>
<pre><code>SpringBoot版本:2.2.5.RELEASE
server.servlet.context-path=/demo
</code></pre>
<p>通过域名访问的url如下:</p>
<pre><code>https://domain.cn/demo
</code></pre>
<p>访问之后url转变为:</p>
<pre><code>http://10.x.1/demo/
</code></pre>
<p>因为网关后面的SpringBoot服务在多个机器部署,转变后的url会变成其中的一台服务器的ip。</p>
<p>在nginx机器上看了下日志,发现请求有一个302重定向的过程,然后变成了SpringBoot的404页面,因为根路径没有对应的handler处理。</p>
<pre><code>Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri Apr 10 23:59:59 CST 2025
There was an unexpected error (type=Not Found, status=404).
No message available
</code></pre>
<p>测试环境,在Chrome中打开F12调试模式,在Network下开启Preserve log,通过SpringBoot服务所在机器的ip和端口直接访问服务的根路径,同样有一个302重定向的过程</p>
<pre><code>http://10.x.1/demo
会转变为
http://10.x.1/demo/
</code></pre>
<p>url在302重定向后,url后面拼接了一个 /</p>
<p>怀疑是不是SpringBoot有什么特殊处理,SpringBoot中是通过<em>org.springframework.web.servlet.DispatcherServlet:doDispatch</em>方法来分发处理请求的,本地调试项目发现<em>doDispatch</em>方法会进入两次,<em>DispatcherServlet</em>上面是tomcat容器了,看样子是容器里了,往上回溯调用链发现<em>org.apache.catalina.mapper.Mapper:internalMapWrapper</em>方法里有一段代码有关于重定向的逻辑,代码如下:</p>
<pre><code>if(mappingData.wrapper == null &amp;&amp; noServletPath &amp;&amp;
      contextVersion.object.getMapperContextRootRedirectEnabled()) {
    // The path is empty, redirect to "/"
    path.append('/');
    pathEnd = path.getEnd();
    mappingData.redirectPath.setChars
      (path.getBuffer(), pathOffset, pathEnd - pathOffset);
    path.setEnd(pathEnd - 1);
    return;
}
</code></pre>
<p>意思就是如果请求的路径是 "" ,那么将重定向到 / ,项目的 <em>server.servlet.context-path=/demo</em>,那么访问根路径,后面不加其它的url,正好就走到了这一个逻辑里面,看代码逻辑是有一个参数可以控制是否重定向的:<em>mapperContextRootRedirectEnabled</em>,这个是<em>org.apache.catalina.core.StandardContext</em>类中的一个配置参数,可以通过配置来修改</p>
<pre><code>server.tomcat.redirect-context-root
</code></pre>
<p>贴一下它的注释:</p>
<pre><code>Determines if requests for a web application context root will be
redirected (adding a trailing slash) by the Mapper. This is more
efficient but has the side effect of confirming that the context path is
valid.
</code></pre>
<p>修改参数的值为false,重启项目再次访问,不再出现302,而是直接到了404页面</p>
<pre><code>server.tomcat.redirect-context-root=false
</code></pre>
<hr>
<p>如果项目的context-path是 / 没有302重定向的过程。</p>
<p>有项目使用了undertow作为容器,但是看了下undertow的代码,发现没有提供类似的参数,后面写一篇文章来记录使用undertow作为容器时出现这样情况的解决方案。</p>
<p>tomcat作为老牌的容器,相较undertow还是有更多灵活的配置选项。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:杜劲松,转载请注明原文链接:https://www.cnblogs.com/imadc/p/18820909</p><br><br>
来源:https://www.cnblogs.com/imadc/p/18820909
頁: [1]
查看完整版本: Spring Boot 使用 Tomcat 作为容器时访问根 context-path 302分析