Home > Blockchain >  How to mask Apache Version on Error Page of Spring Boot application?
How to mask Apache Version on Error Page of Spring Boot application?

Time:12-02

I have a spring boot application with embedded tomcat , whenever there is a server error occurs, I want to hide the apache tomcat version on error page.

As far as I know; the most known solutions are adding server.properties to web.xml or zipping the catalina jar.

Since the application does not have web.xml, I can't figure it out to hide tomcat version.

Tomcat server properties were changed as below but none of them worked.

  • server.error.include-stacktrace=never

  • server.error.whitelabel.enabled=false

Spring boot version : 2.5.4

Please refer the picture.

Thanks!

enter image description here

CodePudding user response:

It may be same issue as following:


import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ErrorReportValve;
import org.apache.coyote.ActionCode;
import org.apache.tomcat.util.ExceptionUtils;

public class CustomErrorReportValve extends ErrorReportValve {

    // Create a simple logger
    Logger log = Logger.getLogger(CustomErrorReportValve.class.getName());

    @Override
    protected void report(final Request request, final Response response, final Throwable throwable) {
        // ref: ErrorReportValve implementation

        final int statusCode = response.getStatus();

        // Do nothing on a 1xx, 2xx and 3xx status
        // Do nothing if anything has been written already
        // Do nothing if the response hasn't been explicitly marked as in error
        //    and that error has not been reported.
        if (statusCode < 400 || response.getContentWritten() > 0 || !response.setErrorReported()) {
            return;
        }

        // If an error has occurred that prevents further I/O, don't waste time
        // producing an error report that will never be read
        final AtomicBoolean result = new AtomicBoolean(false);
        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
        if (!result.get()) {
            return;
        }

        try {
            try {
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
            } catch (final Throwable t) {
                ExceptionUtils.handleThrowable(t);
                if (container.getLogger().isDebugEnabled()) {
                    container.getLogger().debug("status.setContentType", t);
                }
            }
            final Writer writer = response.getReporter();
            if (writer != null) {
                // If writer is null, it's an indication that the response has
                // been hard committed already, which should never happen
                writer.write("<!doctype html><html lang=\"en\"><title>error</title><body>Error occured.</body></html>");
                response.finishResponse();
            }
        } catch (IOException | IllegalStateException e) {
            // Ignore
        }
    }
}
import org.apache.catalina.Container;
import org.apache.catalina.core.StandardHost;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyConfig {
    // https://docs.spring.io/spring-boot/docs/2.5.4/reference/htmlsingle/#howto-use-tomcat-legacycookieprocessor
    // https://github.com/spring-projects/spring-boot/issues/21257#issuecomment-745565376
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> errorReportValveCustomizer() {

        return (factory) -> {
            factory.addContextCustomizers(context -> {
                final Container parent = context.getParent();
                if (parent instanceof StandardHost) {
                    // above class FQCN
                    ((StandardHost) parent).setErrorReportValveClass(
                        "com.example.foo.bar.CustomErrorReportValve");
                }
            });
        };
    }
}

CodePudding user response:

For embedded tomcat, I found configuration to override error report valve

Now the response does not have tomcat version.


var host = (StandardHost) tomcat.getHost();

var errorReportValve = new org.apache.catalina.valves.ErrorReportValve();
errorReportValve.setShowReport(false);
errorReportValve.setShowServerInfo(false);
host.addValve(errorReportValve); 


  • Related