介绍

默认情况下,Tomcat 配置为在大多数使用案例中具有相当的安全性。 某些环境可能需要或多或少的安全配置。 本文旨在为可能影响安全性的配置选项提供单一参考点, 并就更改这些选项的预期影响提供一些注释。 目的是提供在评估 Tomcat 安装的安全性时应考虑的配置选项列表。

注意:阅读本文并不能替代阅读和理解详细的配置文档。 有关这些属性的更完整描述,请参阅相关文档页面。

非 Tomcat 设置

Tomcat 配置不应是唯一的防线。 系统中的其他组件(操作系统、网络、数据库等)也应受到保护。

不应在 root 用户下运行 Tomcat。 为 Tomcat 进程创建一个专用用户, 并为该用户提供操作系统所需的最低权限。 例如,应该不能使用 Tomcat 用户远程登录。

还应适当限制文件权限。在 .tar.gz 分发中, 文件和目录不是全局可读的,并且该组没有写入访问权限。 在类似于 Unix 的操作系统上,Tomcat 使用默认 umask 0027 运行, 以维护 Tomcat 运行时创建的文件(e.g. log文件、扩展的 WAR 等)的这些权限。

以 ASF 的 Tomcat 实例为例(其中禁用了自动部署, 并且 Web 应用程序部署为爆炸目录),标准配置是让所有 Tomcat 文件都归 root 所有, 组 Tomcat 并且虽然所有者具有读/写权限,但组只有读取权限,而 world 没有权限。 但 tomcat 用户而不是 root 拥有的 logs、temp 和 work 目录除外。 这意味着,即使攻击者破坏了 Tomcat 进程, 他们也无法更改 Tomcat 配置、部署新的 Web 应用程序或修改现有的 Web 应用程序。 Tomcat 进程使用 umask 007 运行以维护这些权限。

在网络级别,请考虑使用防火墙将传入和传出连接 限制为仅具有希望存在的那些连接。

JMX

JMX 连接的安全性取决于 JRE 提供的实现, 因此不受 Tomcat 的控制。

通常,访问控制非常有限(对所有内容只读或对所有内容进行读写)。 Tomcat 通过 JMX 公开了大量的内部信息和控制,以帮助调试、监控和管理。 鉴于可用的访问控制有限,JMX 访问应被视为等同于 本地 root/admin 访问,并相应地进行限制。

大多数(所有的?)JRE 供应商不会记录失败的身份验证尝试, 也不会在重复身份验证失败后提供帐户锁定功能。 这使得暴力攻击易于实施且难以检测。

鉴于上述所有内容,应注意确保在使用 JMX 接口时得到适当保护。 可能希望考虑保护 JMX 接口的选项包括:

  • 为所有 JMX 用户配置强密码;

  • 仅将 JMX 侦听器绑定到内部网络;

  • 将对 JMX 端口的网络访问限制为受信任的客户端;和

  • 提供应用程序特定的运行状况页面,供外部监控系统使用。

默认 Web 应用程序

常规

Tomcat 附带了许多默认启用的 Web 应用程序。 过去曾在这些应用程序中发现漏洞。应删除不需要的应用程序, 以便在发现其他漏洞时系统不会面临风险。

ROOT Web 应用程序的安全风险非常低,但确实包括正在使用的 Tomcat 版本。 通常,应该从可公开访问的 Tomcat 实例中删除 ROOT Web 应用程序, 不是出于安全原因,而是为了向用户显示更合适的默认页面。

文档

文档 Web 应用程序的安全风险非常低,但确实可以识别正在使用的 Tomcat 版本。 通常应将其从可公开访问的 Tomcat 实例中删除。

例子

应始终从任何安全敏感安装中删除示例 Web 应用程序。 虽然示例 Web 应用程序不包含任何已知漏洞,但已知它包含一些功能 (特别是显示收到的所有 Cookie 的内容并允许设置新 Cookie 的 Cookie 示例), 攻击者可能会将这些漏洞与 Tomcat 实例上部署的其他应用程序中的漏洞结合使用, 以获取其他方式不可用的其他信息。

管理器

Manager 应用程序允许远程部署 Web 应用程序, 由于广泛使用弱密码和启用了 Manager 应用程序 且可公开访问的 Tomcat 实例,因此经常成为攻击者的目标。 默认情况下,Manager 应用程序不可访问, 因为没有用户配置必要的访问权限。 如果启用了 Manager 应用程序,则应遵循 保护管理应用程序 部分中的指导。

主机管理器

Host Manager 应用程序允许创建和管理虚拟主机 - 包括为虚拟主机启用 Manager 应用程序。 默认情况下,Host Manager 应用程序不可访问, 因为没有用户配置必要的访问权限。 如果启用了 Host Manager 应用程序, 则应遵循 保护管理应用程序 部分中的指导。

保护管理应用程序

在部署为 Tomcat 实例提供管理功能的 Web 应用程序时, 应遵循以下准则:

  • 确保允许访问管理应用程序的任何用户都使用强密码。

  • 不要取消 LockOutRealm 的使用,以防止对用户密码的暴力攻击。

  • 在管理应用程序的 context.xml 文件中配置 RemoteCIDRValve

默认情况下,该文件限制对 localhost 的访问。 如果需要远程访问,请使用此阀将其限制为特定的 IP 地址。

用户 Web 应用程序

Web 应用程序被假定为可信的。从不可信来源部署 Web 应用程序是不安全的。

任何允许修改 Web 应用程序的功能(如 WebDAV、HTTP PUT 请求等), 都可能影响 Web 应用程序或其运行的 Tomcat 实例的安全性。 此类功能应仅限于受信任的用户使用,或在范围上加以限制(例如通过安全约束), 以确保有权限访问这些功能的用户无法影响 Web 应用程序或 Tomcat 实例的安全性。

考虑在部署的 Web 应用程序中使用 CORS 过滤器和/或 CSRF 防护过滤器。

安全管理器

启用安全管理器会将 Web 应用程序运行在沙箱中, 从而显著限制 Web 应用程序执行恶意操作的能力, 例如调用 System.exit()、建立网络连接或访问 Web 应用程序根目录和临时目录之外的文件系统。 然而,需要注意的是,有些恶意操作(如通过无限循环触发高 CPU 占用)安全管理器无法阻止。

启用安全管理器通常是为了在攻击者找到方法入侵可信 Web 应用程序时,限制潜在的影响 。安全管理器也可以用于降低运行不受信任的 Web 应用程序的风险(例如在托管环境中), 但需注意安全管理器只能降低风险,并不能完全消除风险。 如果运行多个不受信任的 Web 应用程序, 建议将每个 Web 应用程序部署到单独的 Tomcat 实例(最好在不同主机上), 以减少恶意 Web 应用程序影响其他应用可用性的可能性。

Tomcat 在启用安全管理器的情况下进行了测试; 但大多数 Tomcat 用户并不启用安全管理器,因此 Tomcat 在这种配置下的用户测试不够充分。 已经并且仍在不断出现报告,指出在安全管理器下运行会触发一些错误。

如果启用安全管理器,其施加的限制很可能会破坏大多数应用程序。 因此,不应在未经广泛测试的情况下使用安全管理器。 理想情况下,安全管理器的使用应在开发周期开始时引入, 因为在成熟应用程序中启用安全管理器后再追踪和修复问题可能耗费大量时间。

启用安全管理器会更改以下设置的默认值:

  • Host 元素的 deployXML 属性默认值将更改为 false

server.xml

常规

默认server.xml包含大量注释,包括一些被注释掉的示例组件定义。 删除这些注释会使阅读和理解server.xml变得相当容易。

如果未列出组件类型,则表示该类型没有直接影响安全性的设置。

服务器

port 属性设置为 -1 将禁用关闭端口。

如果未禁用关闭端口,则应为 关闭 配置强密码。

侦听器

如果使用 gcc 在 Solaris 上编译 APR 生命周期侦听器,则 APR 生命周期侦听器不稳定。 如果在 Solaris 上使用 APR/本机连接器,请使用 Sun Studio 编译器对其进行编译。

JNI Library Loading Listener 可用于加载本机代码。它只应用于加载受信任的库。

应根据需要启用和配置 Security Lifecycle Listener。

连接器

默认情况下,在端口 8080 上配置了非 TLS 的 HTTP/1.1 连接器。 不使用的连接器应从 server.xml 中删除。

AJP 是一种明文协议。AJP 连接器通常只能在受信任的网络上使用。 如果在不受信任的网络上使用,则使用 secret 属性将限制对授权客户端的访问, 但 secret 属性将对任何可以观察网络流量的人可见。

AJP 连接器会阻止具有未知请求属性的转发请求。 通过为 allowedRequestAttributesPattern 属性配置适当的正则表达式, 可以允许已知的 safe 和/或 expected 属性。

address 属性可用于控制连接器侦听连接的 IP 地址。 默认情况下,连接器侦听所有配置的 IP 地址。

allowBackslash 属性允许对请求 URI 进行非标准解析。 在反向代理后面时将此属性设置为非默认值, 可能会使攻击者绕过代理强制执行的任何安全约束。

allowTrace 属性可用于启用 TRACE 请求,这对于调试很有用。 由于某些浏览器处理来自 TRACE 请求的响应的方式(这会使浏览器受到 XSS 攻击), 因此默认情况下对 TRACE 请求的支持处于禁用状态。

discardFacades 属性设置为 true 将导致为每个请求创建一个新的 Facade 对象。 这是默认值,这降低了应用程序中出现 bug 将数据从一个请求公开到另一个请求的可能性。

encodedSolidusHandling 属性允许对请求 URI 进行非标准解析。 在反向代理后面时将此属性设置为非默认值可能会使攻击者绕过代理强制执行的任何安全约束。

maxParameterCount 属性控制从查询字符串获取的请求参数(包括上传的文件)的最大总数, 对于 POST 请求,如果内容类型为 application/x-www-form-urlencodedmultipart/form-data,则控制请求正文。参数过多的请求将被拒绝。

maxPartCount 属性控制 multipart 请求支持的最大部分数。 默认限制为 50,以减少遭受拒绝服务攻击(DoS)的风险。 关于处理 multipart 请求所需内存的更多详细信息,请参阅 maxPartCount 的文档。 部分过多的请求将被拒绝。

maxPostSize 属性控制将针对参数进行解析的 POST 请求的最大大小。 参数在请求期间缓存,因此默认情况下限制为 2 MiB,以减少 DOS 攻击的风险。

maxSavePostSize 属性控制在 FORM 和 CLIENT-CERT 身份验证 以及 HTTP/1.1 升级期间请求正文的保存。对于 FORM 身份验证, 请求正文在身份验证期间缓存在 HTTP 会话中, 因此默认情况下缓存的请求正文限制为 4 KiB,以减少遭受 DOS 攻击的风险。 为了通过限制 FORM 身份验证的允许持续时间来进一步减少 DoS 攻击的风险, 如果会话是由 FORM 身份验证创建的,则使用缩短的会话超时。 这种减少的超时由 FORM 身份验证器的 authenticationSessionTimeout 属性控制。

requiredSecret AJP 连接器中的属性,在 Tomcat 和反向代理之间配置共享密钥。 它用于防止通过 AJP 协议进行未经授权的连接。

server 属性控制 Server HTTP 标头的值。 对于 Tomcat 4.1.x 到 8.0.x,此标头的默认值为 Apache-Coyote/1.1。 从 8.5.x 开始,默认情况下不设置此标头。 此标头可以向合法客户端和攻击者提供有限的信息。

SSLEnabledschemesecure 属性都可以单独设置。 当 Tomcat 位于反向代理后面并且代理通过 HTTP 或 HTTPS 连接到 Tomcat 时, 通常会使用这些选项。它们允许 Tomcat 查看客户端和代理之间连接的 SSL 属性, 而不是代理和 Tomcat 之间的连接。例如,客户端可以通过 HTTPS 连接到代理, 但代理使用 HTTP 连接到 Tomcat。如果 Tomcat 必须能够区分代理接收的安全连接和非安全连接, 则代理必须使用单独的连接器将安全请求和非安全请求传递给 Tomcat。 如果代理使用 AJP,则客户端连接的 SSL 属性将通过 AJP 协议传递,并且不需要单独的连接器。

tomcatAuthenticationtomcatAuthorization 属性与 AJP 连接器一起使用, 以确定 Tomcat 是否应处理所有身份验证和授权,或者是否应将身份验证委托给反向代理 (经过身份验证的用户名作为 AJP 协议的一部分传递给 Tomcat),并可选择 Tomcat 仍执行授权。

xpoweredBy 属性控制是否随每个请求一起发送 X-Powered-By HTTP 标头。 如果发送,则标头的值包含 Servlet 和 JSP 规范版本、 完整的 Tomcat 版本(例如 Apache Tomcat/11.0)、JVM 供应商的名称和 JVM 的版本。 默认情况下,此标头处于禁用状态。 此标头可以为合法客户端和攻击者提供有用的信息。

主机

主机元素控制部署。自动部署可以简化管理,但也使攻击者更容易部署恶意应用程序。 自动部署由 autoDeploydeployOnStartup 属性控制。 如果两者都为 false,则仅部署 server.xml 中定义的上下文, 并且任何更改都需要重新启动 Tomcat。

在 Web 应用程序可能不受信任的托管环境中, 将 deployXML 属性设置为 false 以忽略与 Web 应用程序打包的任何context.xml, 这些可能会尝试为 Web 应用程序分配更高的权限。 请注意,如果启用了安全管理器,则 deployXML 属性将默认为 false

上下文

这适用于所有可以定义它们的位置的 Context 元素: server.xml 文件、默认 context.xml 文件、 每个主机的 context.xml.default 文件、 每个主机配置目录中或 Web 应用程序内的 Web 应用程序上下文文件。

crossContext 属性控制是否允许上下文访问另一个上下文的资源。 默认情况下,它是 false,并且只应针对受信任的 Web 应用程序进行更改。

privileged 属性控制是否允许上下文使用容器提供的 Servlet,如 Manager Servlet。 默认情况下,它是 false,并且只应针对受信任的 Web 应用程序进行更改。

allowLinking 嵌套 Resources 元素的属性控制是否允许上下文使用链接文件。 如果启用且上下文已取消部署,则在删除上下文资源时将跟踪这些链接。 在不区分大小写的操作系统(包括 Windows)上将此设置从默认值 false 更改为默认值, 将禁用许多安全措施,并允许直接访问 WEB-INF 目录等。

sessionCookiePathUsesTrailingSlash 可用于解决许多浏览器 (Internet Explorer、Safari 和 Edge)中的错误, 以防止当应用程序共享公共路径前缀时跨应用程序公开会话 Cookie。 但是,启用此选项可能会给 Servlet 映射到 /* 的应用程序带来问题。 还应注意的是,RFC6265第 8.5 节明确指出, 不应认为不同的路径足以将 Cookie 与其他应用程序隔离开来。

antiResourceLocking 启用后, Tomcat 会将解压缩的 Web 应用程序复制到 java.io.tmpdir 系统属性 (默认为 $CATALINA_BASE/temp)定义的目录。 此位置应使用适当的文件权限进行保护 - 通常为 Tomcat 用户读/写,其他用户无权访问。

当启用 mapperContextRootRedirectEnabled 和/或 mapperDirectoryRedirectEnabled 时, 请求处理将更加高效,但会带来安全副作用。 首先,即使用户没有访问该目录的权限,也可能确认 web 应用程序或目录的存在。 其次,任何 Valve 和/或 Filter——包括提供安全功能的组件——将无法处理该请求。

Valves

强烈建议配置 AccessLogValve。默认的 Tomcat 配置包括一个 AccessLogValve。 这些通常按主机配置,但也可以根据需要按引擎或情景配置。

任何管理应用程序都应由 RemoteAddrValve 保护 (此 Valve 也可用作 Filter)。 allow 属性应用于限制对一组已知受信任主机的访问。

默认 ErrorReportValve 在发送给客户端的响应中包含 Tomcat 版本号。 为避免这种情况,可以在每个 Web 应用程序中配置自定义错误处理。 或者,可以显式配置 ErrorReportValve 并将其 showServerInfo 属性设置为 false。 或者,可以通过创建文件 CATALINA_BASE/lib/org/apache/catalina/util/ServerInfo.properties 来更改版本号,其内容如下:

server.info=Apache Tomcat/9.0.x

根据需要修改值。请注意,这也会更改某些管理工具中报告的版本号, 并且可能会使确定安装的实际版本变得更加困难。 CATALINA_HOME/bin/version.bat|sh 脚本仍将报告正确的版本号。

发生错误时,默认的 ErrorReportValve 可以向客户端显示堆栈跟踪和/或 JSP 源代码。 为避免这种情况,可以在每个 Web 应用程序中配置自定义错误处理。 或者,可以显式配置 ErrorReportValve 并将其 showReport 属性设置为 false

RewriteValve 使用正则表达式,格式不正确的正则表达式模式 可能容易受到 “灾难性回溯” 或 “ReDoS” 的影响。 有关更多详细信息,请参阅 重写文档 。

Realms

MemoryRealm 不用于生产环境, 因为对 tomcat-users.xml 的任何更改都需要重新启动 Tomcat 才能生效。

不推荐在生产环境中使用 JDBCRealm, 因为它对所有身份验证和授权选项都是单线程的。请改用 DataSourceRealm。

UserDatabaseRealm 不适用于大规模安装。 它适用于小规模、相对静态的环境。

JAASRealm 没有得到广泛使用,因此该代码不如其他领域成熟。 建议在使用此领域之前进行其他测试。

默认情况下,领域不实施任何形式的账户锁定。 这意味着暴力攻击可以成功。 为了防止暴力攻击,所选领域应该包装在 LockOutRealm 中。

管理器

管理器组件用于生成会话 ID。

用于生成随机会话 ID 的类可以使用 randomClass 属性进行更改。

会话 ID 的长度可以使用 sessionIdLength 属性进行更改。

persistAuthentication 控制在重新启动期间或将会话保留到 Store 期间保留会话时, 是否包含与会话关联的经过身份验证的 Principal(如果有)。

使用 JDBCStore 时,应保护会话存储(专用凭证、适当的权限), 以便只有 JDBCStore 能够访问持久会话数据。 特别是,JDBCStore 不应通过 Web 应用程序可用的任何凭证进行访问。

集群

集群实现的编写基础是,所有与集群相关的网络流量都使用一个安全、可信的网络。 在不安全、不受信任的网络上运行集群是不安全的。

如果需要机密性和/或完整性保护,则可以使用 EncryptInterceptor 来加密节点之间的流量。 此拦截器并不能防止在不受信任的网络上运行的所有风险,尤其是 DoS 攻击。

web.xml

这适用于 Web 应用程序中的默认 conf/web.xml 文件、 /WEB-INF/tomcat-web.xml/WEB-INF/web.xml 文件 (如果它们定义了此处提到的组件)。

DefaultServlet 配置为 readonly 设置为 true。 将此项更改为 false 允许客户端删除或修改服务器上的静态资源并上传新资源。 通常,在不需要身份验证的情况下,不应更改此名称。

DefaultServlet 配置为 listings 设置为 false。 这并不是因为允许目录列表被认为是不安全的,而是因为生成包含数千个文件的目录列表会消耗大量 CPU,从而导致 DOS 攻击。

DefaultServlet 配置为 showServerInfotrue。 启用目录列表后,Tomcat 版本号将包含在发送到客户端的响应中。 为避免这种情况,可以显式配置一个 DefaultServlet 并将其 showServerInfo 属性设置为 false。或者,可以通过创建文件 CATALINA_BASE/lib/org/apache/catalina/util/ServerInfo.properties 来更改版本号,其内容如下:

server.info=Apache Tomcat/9.0.x

根据需要修改值。请注意,这也会更改某些管理工具中报告的版本号, 并且可能会使确定安装的实际版本变得更加困难。 CATALINA_HOME/bin/version.bat|sh 脚本仍将报告正确的版本号。

默认情况下,CGI Servlet 处于禁用状态。 如果启用,则 debug initialization 参数 不应在生产系统上设置为 10 或更高,因为 debug 页面不安全。

在启用了 enableCmdLineArguments 的情况下在 Windows 上使用 CGI Servlet 时, 请仔细检查 cmdLineArgumentsDecoded 的设置,并确保它适合环境。 默认值为 secure。不安全的配置可能会使服务器暴露于远程代码执行中。 有关潜在风险和缓解措施的更多信息,请点击 CGI 操作指南中的链接。

FailedRequestFilter 可以配置并用于拒绝在请求参数解析过程中发生错误的请求。 没有该过滤器时,默认行为是忽略无效或过多的参数。

HttpHeaderSecurityFilter 可用于向响应添加标头以提高安全性。 如果客户端直接访问 Tomcat,那么可能希望启用此过滤器及其设置的所有标头, 除非应用程序已经设置了它们。如果通过反向代理访问 Tomcat, 则此过滤器的配置需要与反向代理设置的任何 Headers 进行协调。

WebDAV servlet 使 Web 应用内容的编辑功能成为可能。 如果启用了 WebDAV servlet,则应对 WebDAV 功能进行适当的安全保护。 如果预计有任何合法用户会通过浏览器访问 Web 应用,则应包括 CORS 保护。

在配置安全约束时,如果一个或多个约束的 URL 模式覆盖了成为 servlet pathInfo 部分的 URL 段, 并且该 servlet 使用 pathInfo 来识别其他资源(如默认 servlet 所做的那样), 则应特别注意。在这些情况下,安全约束的正确应用取决于 Servlet 的实现。 Tomcat 附带的所有 servlet 在这种情况下都会正确运行。

嵌入式 Tomcat

使用嵌入式 Tomcat 时,不会设置脚本、 server.xml和其他配置提供的典型默认值。 嵌入式 Tomcat 的用户可能希望考虑以下事项:

  • 默认情况下,通常以 server.xml 配置的侦听器 (包括 org.apache.catalina.security.SecurityListener) 将不进行配置。如果需要,必须显式启用它们。

  • java.io.tmpdir 将不会被设置(通常设置为 $CATALINA_BASE/temp)。 此目录用于可能对安全敏感的各种临时文件,包括文件上传和 Web 应用程序的副本 (如果启用了反资源锁定)。请考虑将 java.io.tmpdir 系统属性设置为适当安全的目录。

反向代理

所有客户端,包括反向代理,都需要对向 Tomcat 提供的数据的后果负责。

Servlet 规范在规范化请求时会移除路径参数。HTTP 服务器通常不会这样做。 这就可能导致客户端在 URI 中使用 /..;a=b/ 之类的序列来绕过在反向代理中实施的安全约束。 这种可能性可以通过适当的配置来避免,例如在 httpd 的 mod_proxy 中使用 mapping=servlet 设置。

如果 Tomcat 部署在反向代理之后,并且该反向代理实施了一个或多个安全约束, 建议采取纵深防御的方法来确保 Tomcat 的安全,就像没有使用反向代理一样。

常规

BASIC 和 FORM 身份验证以明文形式传递用户名和密码。 将这些身份验证机制与通过不受信任的网络连接的客户端一起使用的 Web 应用程序应使用 SSL。

对于攻击者来说,与经过身份验证的用户进行会话的会话 Cookie 几乎与用户密码一样有用, 并且应该提供与密码本身相同级别的保护。 这通常意味着通过 SSL 进行身份验证并继续使用 SSL 直到会话结束。

Tomcat 对 Servlet API 的文件上传支持的实现可以使用 java.io.tmpdir 系统属性(默认为 $CATALINA_BASE/temp)定义的目录来存储临时文件。 此位置应使用适当的文件权限进行保护 - 通常为 Tomcat 用户读/写,其他用户无权访问。