介绍
默认情况下,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
文件中配置RemoteAddrValve
, 默认情况下,该文件限制对 localhost 的访问。 如果需要远程访问,请使用此阀将其限制为特定的 IP 地址。
安全管理器
从 Tomcat 11 开始,已删除对在安全管理器下运行的支持。 类似(可以说是更好的)功能可以通过在专用环境(如容器或 VM)中的 专用 Tomcat 实例上运行单个 Web 应用程序来获得。
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 进行非标准解析。 在反向代理后面时将此属性设置为非默认值可能会使攻击者绕过代理强制执行的任何安全约束。
enforceEncodingInGetWriter 属性设置为 false
,则具有安全隐患。
许多用户代理违反 RFC 7230,在应使用 ISO-8859-1 的规范强制默认值时,
试图猜测文本媒体类型的字符编码。
某些浏览器会将包含对 ISO-8859-1 安全的字符的响应解释为 UTF-7,
但如果解释为 UTF-7 则会触发 XSS 漏洞。
maxPostSize 属性控制将针对参数进行解析的 POST 请求的最大大小。 参数在请求期间缓存,因此默认情况下限制为 2 MiB,以减少 DOS 攻击的风险。
maxSavePostSize 属性控制在 FORM 和 CLIENT-CERT 身份验证
以及 HTTP/1.1 升级期间请求正文的保存。对于 FORM 身份验证,
请求正文在身份验证期间缓存在 HTTP 会话中,
因此默认情况下缓存的请求正文限制为 4 KiB,以减少遭受 DOS 攻击的风险。
为了通过限制 FORM 身份验证的允许持续时间来进一步减少 DoS 攻击的风险,
如果会话是由 FORM 身份验证创建的,则使用缩短的会话超时。
这种减少的超时由 FORM 身份验证器的 authenticationSessionTimeout
属性控制。
maxParameterCount 属性控制从查询字符串获取的请求参数(包括上传的文件)的最大总数,
对于 POST 请求,如果内容类型为 application/x-www-form-urlencoded
或 multipart/form-data
,则控制请求正文。参数过多的请求将被拒绝。
xpoweredBy 属性控制是否随每个请求一起发送 X-Powered-By HTTP 标头。 如果发送,则标头的值包含 Servlet 和 JSP 规范版本、 完整的 Tomcat 版本(例如 Apache Tomcat/11.0)、JVM 供应商的名称和 JVM 的版本。 默认情况下,此标头处于禁用状态。 此标头可以为合法客户端和攻击者提供有用的信息。
server 属性控制 Server HTTP 标头的值。 对于 Tomcat 4.1.x 到 8.0.x,此标头的默认值为 Apache-Coyote/1.1。 从 8.5.x 开始,默认情况下不设置此标头。 此标头可以向合法客户端和攻击者提供有限的信息。
SSLEnabled、scheme 和 secure 属性都可以单独设置。 当 Tomcat 位于反向代理后面并且代理通过 HTTP 或 HTTPS 连接到 Tomcat 时, 通常会使用这些选项。它们允许 Tomcat 查看客户端和代理之间连接的 SSL 属性, 而不是代理和 Tomcat 之间的连接。例如,客户端可以通过 HTTPS 连接到代理, 但代理使用 HTTP 连接到 Tomcat。如果 Tomcat 必须能够区分代理接收的安全连接和非安全连接, 则代理必须使用单独的连接器将安全请求和非安全请求传递给 Tomcat。 如果代理使用 AJP,则客户端连接的 SSL 属性将通过 AJP 协议传递,并且不需要单独的连接器。
tomcatAuthentication 和 tomcatAuthorization 属性与 AJP 连接器一起使用, 以确定 Tomcat 是否应处理所有身份验证和授权,或者是否应将身份验证委托给反向代理 (经过身份验证的用户名作为 AJP 协议的一部分传递给 Tomcat),并可选择 Tomcat 仍执行授权。
AJP 连接器中的 requiredSecret 属性在 Tomcat 和反向代理之间配置共享密钥。 它用于防止通过 AJP 协议进行未经授权的连接。
主机
主机元素控制部署。自动部署可以简化管理,但也使攻击者更容易部署恶意应用程序。
自动部署由 autoDeploy 和 deployOnStartup 属性控制。
如果两者都为 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 应用程序进行更改。
嵌套 Resources 元素的 allowLinking 属性控制是否允许上下文使用链接文件。
如果启用且上下文已取消部署,则在删除上下文资源时将跟踪这些链接。
在不区分大小写的操作系统(包括 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 用户读/写,其他用户无权访问。
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/11.0.x
根据需要修改值。请注意,这也会更改某些管理工具中报告的版本号,
并且可能会使确定安装的实际版本变得更加困难。
CATALINA_HOME/bin/version.bat|sh
脚本仍将报告正确的版本号。
发生错误时,默认的 ErrorReportValve 可以向客户端显示堆栈跟踪和/或 JSP 源代码。
为避免这种情况,可以在每个 Web 应用程序中配置自定义错误处理。
或者,可以显式配置 ErrorReportValve 并将其 showReport 属性设置为 false
。
RewriteValve 使用正则表达式,格式不正确的正则表达式模式 可能容易受到 “灾难性回溯” 或 “ReDoS” 的影响。 有关更多详细信息,请参阅 重写文档 。
Realms
MemoryRealm 不用于生产环境, 因为对 tomcat-users.xml 的任何更改都需要重新启动 Tomcat 才能生效。
UserDatabaseRealm 不适用于大规模安装。 它适用于小规模、相对静态的环境。
JAASRealm 没有得到广泛使用,因此该代码不如其他领域成熟。 建议在使用此领域之前进行其他测试。
默认情况下,领域不实施任何形式的账户锁定。 这意味着暴力攻击可以成功。 为了防止暴力攻击,所选领域应该包装在 LockOutRealm 中。
管理器
管理器组件用于生成会话 ID。
用于生成随机会话 ID 的类可以使用 randomClass 属性进行更改。
会话 ID 的长度可以使用 sessionIdLength 属性进行更改。
persistAuthentication 控制在重新启动期间或将会话保留到 Store 期间保留会话时, 是否包含与会话关联的经过身份验证的 Principal(如果有)。
使用 JDBCStore 时,应保护会话存储(专用凭证、适当的权限), 以便只有 JDBCStore 能够访问持久会话数据。 特别是,JDBCStore 不应通过 Web 应用程序可用的任何凭证进行访问。
将会话持久化到集群中的存储或复制会话的 Manager 实现通常使用 Java 序列化。
虽然会话数据被认为是可信的(因为应用程序是可信的),
但系统管理员可能希望考虑对 Java 序列化施加限制。
这可以使用 sessionAttributeValueClassNameFilter 属性来完成。
此属性的安全起始值为
java\\.lang\\.(?:Boolean|Integer|Long|Number|String)|org\\.apache\\.catalina\\.realm\\.GenericPrincipal\\$SerializablePrincipal|\\[Ljava.lang.String;
然后可以对其进行调整以满足应用程序的需要。
如果为 sessionAttributeValueClassNameFilter 设置值,
建议将 warnOnSessionAttributeFilterFailure 设置为 true。
集群
集群实现的编写基础是,所有与集群相关的网络流量都使用一个安全、可信的网络。 在不安全、不受信任的网络上运行集群是不安全的。
如果需要机密性和/或完整性保护,则可以使用 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 配置为 showServerInfo 为 true
。
启用目录列表后,Tomcat 版本号将包含在发送到客户端的响应中。
为避免这种情况,可以显式配置一个 DefaultServlet
并将其 showServerInfo 属性设置为 false
。或者,可以通过创建文件
CATALINA_BASE/lib/org/apache/catalina/util/ServerInfo.properties
来更改版本号,其内容如下:
server.info=Apache Tomcat/11.0.x
根据需要修改值。请注意,这也会更改某些管理工具中报告的版本号,
并且可能会使确定安装的实际版本变得更加困难。
CATALINA_HOME/bin/version.bat|sh
脚本仍将报告正确的版本号。
默认情况下,CGI Servlet 处于禁用状态。
如果启用,则 debug initialization 参数
不应在生产系统上设置为 10
或更高,因为 debug 页面不安全。
在启用了 enableCmdLineArguments
的情况下在 Windows 上使用 CGI Servlet 时,
请仔细检查 cmdLineArgumentsDecoded
的设置,并确保它适合环境。
默认值为 secure
。不安全的配置可能会使服务器暴露于远程代码执行中。
有关潜在风险和缓解措施的更多信息,请点击 CGI 操作指南中的链接。
HttpHeaderSecurityFilter
可用于向响应添加标头以提高安全性。
如果客户端直接访问 Tomcat,那么可能希望启用此过滤器及其设置的所有标头,
除非应用程序已经设置了它们。如果通过反向代理访问 Tomcat,
则此过滤器的配置需要与反向代理设置的任何 Headers 进行协调。
嵌入式 Tomcat
使用嵌入式 Tomcat 时,不会设置脚本、 server.xml和其他配置提供的典型默认值。 嵌入式 Tomcat 的用户可能希望考虑以下事项:
-
默认情况下,通常以
server.xml
配置的侦听器 (包括org.apache.catalina.security.SecurityListener
) 将不进行配置。如果需要,必须显式启用它们。 -
java.io.tmpdir
将不会被设置(通常设置为$CATALINA_BASE/temp
)。 此目录用于可能对安全敏感的各种临时文件,包括文件上传和 Web 应用程序的副本 (如果启用了反资源锁定)。请考虑将java.io.tmpdir
系统属性设置为适当安全的目录。
常规
BASIC 和 FORM 身份验证以明文形式传递用户名和密码。 将这些身份验证机制与通过不受信任的网络连接的客户端一起使用的 Web 应用程序应使用 SSL。
对于攻击者来说,与经过身份验证的用户进行会话的会话 Cookie 几乎与用户密码一样有用, 并且应该提供与密码本身相同级别的保护。 这通常意味着通过 SSL 进行身份验证并继续使用 SSL 直到会话结束。
Tomcat 对 Servlet API 的文件上传支持的实现可以使用
java.io.tmpdir
系统属性(默认为 $CATALINA_BASE/temp
)定义的目录来存储临时文件。
此位置应使用适当的文件权限进行保护 - 通常为 Tomcat 用户读/写,其他用户无权访问。