Home > Mobile >  How do i catch an HTTP request header parse error thrown by Http11Processor?
How do i catch an HTTP request header parse error thrown by Http11Processor?

Time:08-07

I am running a spring boot application with an embedded Tomcat server on an AWS EC2 instance. I use Log4J2 to log both the spring boot logs as well as the tomcat server logs.

Tomcat will usually display a log that includes the ip address of the computer that made the request, the endpoint that was requested and how long it took to respond. But this only happens when the application is able to process the request and send a response.

If the request can't be processed because the request header can't be parsed then the Http11Processor will throw an error that is logged but that does not include an ip address.

The log looks like this:

[INFO ] 2022-08-06 22:37:26.363 [http-nio-8080-exec-1] Http11Processor

  • Error parsing HTTP request header Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level. java.lang.IllegalArgumentException: Invalid character found in the request target [/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=HelloThinkPHP21 ]. The valid characters are defined in RFC 7230 and RFC 3986 at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:494) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:271) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar!/:?] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar!/:?] at java.lang.Thread.run(Thread.java:833) ~[?:?]

This error was caused by a bot that was scanning my server for php related vulnerabilities. I want to block this bot but i need the ip address to do that and http11Processor doesn't log that by default.

So i want to catch this exception and log the ip address in the catch clause. My question is: Where should i place this catch clause?

I log the tomcat server logs using a custom AccessLogValve that looks like this:

public class Log4JAccessValve extends AbstractAccessLogValve { 

    private static final Logger httpAccessLogLogger = LogManager.getLogger("http_access_log");

    @Override //https://stackoverflow.com/questions/40172395/how-to-add-an-accesslogvalve-to-tomcat-programmatically
    protected void log(CharArrayWriter message) {
        httpAccessLogLogger.info(message.toString());
    }
}

But i don't think the http11Processor passed through this AccessLogValve or else the log would have mentioned http_access_log instead of http-nio-8080-exec-1. How do i catch the exceptions coming from Http11Processor so that i can alter the error message?

CodePudding user response:

Tomcat is quite strict in respecting the HTTP RFCs, most other software (including major browsers) is not.

As you observed correctly the invalid requests are not logged by your AccessLogValve, because they never leave Tomcat's HTTP server (Coyote). If you want to log those requests, you need to relax Tomcat's URI validator (as e.g. in this question), so that they can be forwarded to Tomcat's valves:

<Connector port="..." ...
           relaxedPathChars="&quot;&lt;&gt;[\]^`{|}"
           relaxedQueryChars="&quot;&lt;&gt;[\]^`{|}"/>

Remark: there are so many bots scanning for vulnerabilities, that I would not bother increasing Tomcat CPU usage just to log their IPs and block them.

CodePudding user response:

There is a non-recommended but effective way that you can customize a Valve and get the Throwable with the following code.

Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

Refer to ErrorReportValve implementation.

  • Related