Hardening & Reverse Proxy
Information Disclosure
Server Header & Stack Trace Suppression

Mask default Apache-Coyote/1.1 banner and eliminate technical stack traces on 404/500 errors.

Proxy Trust Integration
RemoteIpValve Protocol Translation

Accurately restore client IP addresses (X-Forwarded-For) and scheme (X-Forwarded-Proto) from trusted upstream gateways.

Session & Cookie Defenses
HttpOnly, Secure & SameSite Attributes

Harden JSESSIONID cookies against XSS extraction and Cross-Site Request Forgery (CSRF).

1. Mask Server Banner & Suppress Error Stack Traces

Prevent attackers from identifying Tomcat version and software versions during reconnaissance

In $CATALINA_BASE/conf/server.xml, configure the <Connector> element with a masked server attribute, and add the ErrorReportValve inside <Host> to suppress debug traces on error pages.

<!-- 1. Mask the Server HTTP Response Header in server.xml -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxParameterCount="1000"
           server="Web Application Server"
           xpoweredBy="false" />

<!-- 2. Suppress Server Version and Stack Traces inside <Host name="localhost" ...> -->
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

    <!-- ErrorReportValve hides Tomcat version and stack trace from error responses -->
    <Valve className="org.apache.catalina.valves.ErrorReportValve"
           showReport="false"
           showServerInfo="false" />

    <!-- Standard Access Log Valve -->
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b %D" />
</Host>

2. Upstream Reverse Proxy Integration (RemoteIpValve)

Ensure request.getRemoteAddr() and request.isSecure() report the true client IP and HTTPS status

When running behind NGINX, Cloudflare, AWS ALB, or HAProxy, Tomcat sees the proxy IP as the remote client unless RemoteIpValve is configured inside the <Engine> or <Host> container:

<!-- Place inside <Engine name="Catalina" ...> in server.xml -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
       internalProxies="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|10\.\d+\.\d+\.\d+|172\.(1[6-9]|2[0-9]|3[0-1])\.\d+\.\d+|192\.168\.\d+\.\d+"
       remoteIpHeader="x-forwarded-for"
       proxiesHeader="x-forwarded-by"
       protocolHeader="x-forwarded-proto"
       protocolHeaderHttpsValue="https" />

Corresponding NGINX Location Block

Configure NGINX upstream proxy directives to forward the real client IP and TLS status:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;

    # Timeouts and buffers for production stability
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    proxy_buffering on;
    proxy_buffer_size 8k;
    proxy_buffers 8 64k;
}

3. Cookie Hardening & Global Security Filters

Configure $CATALINA_BASE/conf/web.xml and context.xml

In $CATALINA_BASE/conf/context.xml, enforce useHttpOnly and sameSiteCookies on all session cookies:

<!-- In conf/context.xml -->
<Context useHttpOnly="true">
    <!-- SameSite cookie attribute (available in Tomcat 8.5.42+, 9.0.21+, 10.0+) -->
    <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
                     sameSiteCookies="lax" />
</Context>

Global Security Filters in conf/web.xml

<!-- 1. Enforce HTTPS only for Session Cookies -->
<session-config>
    <session-timeout>30</session-timeout>
    <cookie-config>
        <http-only>true</http-only>
        <secure>true</secure>
    </cookie-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>

<!-- 2. HTTP Header Security Filter (HSTS, X-Frame-Options, X-Content-Type-Options) -->
<filter>
    <filter-name>httpHeaderSecurity</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <init-param>
        <param-name>hstsEnabled</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>hstsMaxAgeSeconds</param-name>
        <param-value>31536000</param-value>
    </init-param>
    <init-param>
        <param-name>antiClickJackingOption</param-name>
        <param-value>DENY</param-value>
    </init-param>
    <init-param>
        <param-name>blockContentTypeSniffingEnabled</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>httpHeaderSecurity</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

4. Production Hardening Checklist

Essential defense-in-depth lockdown measures
1. Remove Default Webapps

Delete webapps/ROOT, webapps/docs, webapps/examples, webapps/manager, and webapps/host-manager from production installations.

2. Restrict File System Permissions

Set chmod 640 conf/* and chmod 750 bin/ conf/. Only allow the unprivileged tomcat user write access to logs/, temp/, and work/.

3. Disable Unused Connectors

Comment out unused AJP (8009) or plaintext HTTP connectors in server.xml if terminating TLS at reverse proxy.

4. Set SHUTDOWN Port Security

Set <Server port="-1" shutdown="SHUTDOWN"> to completely disable listening on the TCP shutdown socket in containers/systemd.