Tomcat提供静态内容服务

5

我有一个Spring应用程序,想知道最好的提供静态内容的方式。我尝试了以下方法:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

这样做可以实现功能,但是 DefaultServlet 的行为意味着任何 /static/PATH 形式的请求都会从 webapp/PATH 中提供文件。这暴露了一个严重的漏洞,使得类似以下 URL 的敏感信息可以被展示出来:http://localhost/app/static/META-INF/context.xml 有什么常见的解决方案吗?我应该移动敏感文件吗?编写自己的 DefaultServlet?还是有更好的方法来提供静态内容?

你的“context”或者“docBase”有问题吗? - Déjà vu
3个回答

17

你测试过了吗?根据Servlet规范,/META-INF/WEB-INF文件夹应该是公共的不可访问的。客户端应该会得到404错误。否则,这将是DefaultServlet中的一个错误。

以下是Servlet 2.5规范的摘录:

SRV.9.5目录结构

... 同样,任何客户端请求访问WEB-INF/目录中的资源都必须返回SC_NOT_FOUND(404)响应。

SRV.9.6 Web应用程序归档文件

... 同样,任何访问META-INF目录中的资源的请求都必须返回SC_NOT_FOUND(404)响应。


更新:好的,我收回我的话。我可以在最新的Tomcat 6和7上重现这个问题。这明显是DefaultServlet中的一个bug。在Glassfish 3.0.1上它工作得很好(返回404)。


更新2: 我已将此报告给Tomcat团队作为问题50026


更新3:其中一位Tomcat开发人员回复如下:

我认为这是一个“不修复”的问题。Servlet引擎保护Web应用程序中的WEB-INF和META-INF路径(这很好地工作),而不是任意路径下具有该名称的文件。实际上发生的情况是,您正在配置通用文件服务servlet将整个Web应用程序挂载到不同的路径下,这相当于配置Apache执行相同的操作。但是DefaultServlet不是通用文件服务器 - 它被设计为映射到/,您无法将其配置为执行除从Web应用程序目录中提供文件之外的任何操作。我猜测您正在尝试解决通过将另一个servlet映射到/*引入的问题,这基本上是试图解决servlet引擎的工作方式。如果您正在尝试做这件事,则如何在将全局前端控制器servlet映射到/*时访问静态资源提供了更好的方法示例。自Tomcat存在以来,重新安装DefaultServlet的建议似乎一直存在,因此也许我们需要锁定它(以便人们不能意外创建不安全的配置)或支持挂载特定目录(内部或外部Web应用程序),并在任何情况下都会在映射到子路径时中断访问根资源。

更新4:他们最终修复了它:

针对DefaultServlet和WebdavServlet的修复已提交至7.0.x(将包含在7.0.4+中),并提议用于6.0.x。 需要检查5.5.x并确定是否需要回溯。


我已经测试过了,我可以清楚地看到我的context.xml文件,里面包含了我的数据库密码。 - Steve
1
要么你把 WEB-INFMETA-INF 文件夹放错位置了(它们必须放在 webcontent 根目录下,而不是像 /static 这样的子文件夹中),要么使用的 Tomcat 版本存在 bug。 - BalusC
Tomcat 6的确是如此工作的。即使Spring的Petclinic示例也存在漏洞 https://src.springframework.org/svn/spring-samples/petclinic/trunk/ 真的,只能说惊人。 - axtavt
刚拿到了一个全新的Tomcat 6,一个在Eclipse中崭新的动态Web项目,并只添加了以下内容到web.xml,我就可以访问META-INF了: <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping> - Steve
我收回之前的话,我可以复现这个。这太棒了。 - BalusC

11

有几种更好的方法来提供静态内容。

传统方法是使用UrlRewriteFilter将URL进行重定向:

web.xml:

<filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
...
<servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/app/*</url-pattern>
</servlet-mapping>

urlrewrite.xml:


(直接翻译)这是一个名为urlrewrite.xml的文件:
<urlrewrite default-match-type="wildcard">
    <rule>
        <from>/images/**</from>
        <to>/images/$1</to>
    </rule>
    <rule>
        <from>/scripts/**</from>
        <to>/scripts/$1</to>
    </rule>
    <rule>
        <from>/styles/**</from>
        <to>/styles/$1</to>
    </rule>
    <rule>
        <from>/**</from>
        <to>/app/$1</to>
    </rule>
</urlrewrite>

在大多数Spring示例中都可以看到这种方法。


Spring 3.0.1引入了一种更新的方法——可以通过DispatcherServlet提供静态内容。它可以使用Spring配置文件中的<mvc:resource>元素进行配置。在Spring 3.0.4中,它得到了多位置和缓存控制选项的支持,参见15.12.4 mvc:resources


@BalusC:这两种方法都可以解决这个问题——前者通过显式排除将/*重新映射到/app/*,后者则通过将静态内容通过映射到/DispatcherServlet来提供服务。 - axtavt
根据我的经验,需要使用Spring 3.0.4才能识别<mvc:resource>标签(而不是3.0.1)。 - Juan Calero

1

WEB-INFMETA-INF是私有文件夹。客户端必须收到404错误。因为META_INF的内容不能直接访问。否则,请将所有敏感文件移动到WEB_INF中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接