Strange requests in access logs lead to IllegalArgumentException - java

I am using tomcat8.0.43 as my server.
When reviewing my logs, occasionally I see:
[...]INFO[...] org.apache.coyote.http11.AbstractHttp11Processor.process
Error parsing HTTP request header
Note: further occurrences of HTTP
header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the
HTTP protocol
Or:
java.lang.IllegalArgumentException: Invalid character found in the
request target. The valid characters are defined in RFC 7230 and RFC
3986
If I look at my access logs, I see that the urls that were requested to yield these exceptions were things like:
"GET /scripts/index.php?OPT_Session= null" 400
or:
"GET null null" 400
Was I correct in identifying the requests that caused the exceptions to be thrown?
Is there anything that I can do to stop these exceptions from being thrown or restrict these requests from being made?
A normal browser doesn't even allow a client to enter a url with a space in it. It appears these requests do have spaces in them though.
Thanks.

The requests are most probably attacks. If you are running an Internet-facing web server you have to live with them. It is fairly common to put a web server such as Apache in front of Tomcat, possibly configured with mod_security (https://modsecurity.org). In addition you could use fail2ban or a similar solution in order to ban IPs based on errors in the log. However, in my recent experience attackers tend to use a wide range of IP addresses, so fail2ban may not be very effective.

Related

Tomcat 9: header line does not conform to RFC 7230

I have an app that was working on Tomcat 8.5.38.
Now I decided upgrade to Tomcat 9.0.27 and there appears problem with GET request and RFC 7230, Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing.
The request:
/api/vehicle/power_off?vehicleId=1428714&dtStart=2019-10-21 08:00:00&dtEnd=2019-10-21 08:30:00
It was working perfectly from both browser (any - IE, Opera, Chrome, FF) and another client (1C ERP system).
After version upgrade from browser it still works perfectly but from 1C don't. Tomcat shows error:
28-Oct-2019 17:29:26.201 INFO [http-nio-8080-exec-3] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header
Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: The HTTP header line [get /api/vehicle/power_off?deviceId=1428714&dtStart=2019-10-21%2008:00:00&dtEnd=2019-10-21%2008:30:00 HTTP/1.1: ] does not conform to RFC 7230 and has been ignored.
at org.apache.coyote.http11.Http11InputBuffer.skipLine(Http11InputBuffer.java:962)
at org.apache.coyote.http11.Http11InputBuffer.parseHeader(Http11InputBuffer.java:825)
at org.apache.coyote.http11.Http11InputBuffer.parseHeaders(Http11InputBuffer.java:564)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:309)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
The same error is on my dev machine (MacOS + Tomcat 9.0.24) and production server (Ubuntu 16.04 + Tomcat 9.0.27).
The reason is in colon in datetime parameters. When I remove colons from query string (leave just "2019-10-21 080000") the request works as expected (with error "datetime cannot be parsed..."). Also when I manually change colons to "%3A" the request works and returns normal result.
Then I add relaxedQueryChars parameter to Tomcat Connector with colon (though colon is allowed symbol):
relaxedQueryChars=':[]|{}^\`"<>'
and it still fails.
What's the difference between 8 and 9 Tomcat versions that my request works in 8 but in 9 do not?
Is there anything I can do in Tomcat to make this request works? Changing requests on client sides is very hard task...
What's the difference between 8 and 9 Tomcat versions that my request
works in 8 but in 9 do not?
I think the difference is that Tomcat 9.x has tightened up on what should be permitted to be unencoded within a URL, so from a technical perspective there is no problem with Tomcat 9.x; the issue lies with earlier Tomcat releases, and browsers not strictly following specifications.
That said, I couldn't identify any specific fix that has triggered this issue for you, nor could I see anything in the Release Notes.
I add relaxedQueryChars parameter to Tomcat Connector with colon
(though colon is allowed symbol)...and it still fails.
From the Tomcat 9.0 documentation for relaxedQueryChars:
The HTTP/1.1 specification requires that certain characters are %nn encoded when used in URI query strings. Unfortunately, many user agents including all the major browsers are not compliant with this specification and use these characters in unencoded form. To prevent Tomcat rejecting such requests, this attribute may be used to specify the additional characters to allow. If not specified, no additional characters will be allowed. The value may be any combination of the following characters: " < > [ \ ] ^ ` { | } . Any other characters present in the value will be ignored.
Note the last two sentences. The colon character is not mentioned, so it "will be ignored".
Is there anything I can do in Tomcat to make this request work?
I don't think so, but the real problem is that you are not encoding colons within your parameters, and you have already mentioned that this resolves the issue. See this SO answer, and in particular the final sentence:
There are reserved characters, that have a reserved meanings, those are delimiters — :/?#[]# — and subdelimiters — !$&'()*+,;=
There is also a set of characters called unreserved characters — alphanumerics and -._~ — which are not to be encoded.
That means, that anything that doesn't belong to unreserved characters set is supposed to be %-encoded, when they do not have special meaning (e.g. when passed as a part of GET parameter).
The colon is a reserved character with a special meaning, and therefore it must be encoded within your parameters.
Notes:
Also see Bug 62273 - Add support for alternate URL specification. Although it doesn't specifically address your issue with the colon character, there is an interesting discussion on how browsers have not been adhering to RFC 3986 (Uniform Resource Identifier (URI): Generic Syntax).
The error message you are getting from Tomcat is vague, and could probably be improved. Perhaps raise a bug report with them?
In my case, I had increased the request header size by manually adding new cookies onto the Curl request.
In doing so, ENTER key was used instead of space.
Backspacing & using a space instead resolved the issue for me.

Error 404--Not Found The server has not found anything matching the Request-URI

I am getting below error while executing the code
Error 404--Not Found
From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.
If the server does not wish to make this information available to the client, the status code 403 (Forbidden) can be used instead.
The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address.
As I can see URI is correct and still getting the above mentioned error.

Tomcat: custom error page instead of empty response

Some requests are rejected by Tomcat with an empty HTTP 400 response.
A couple of examples:
A request url containing unencoded characters (e.g. '[' or ']' since Tomcat 8.5.x) triggers:
INFO o.a.c.h.Http11Processor Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
A 400 error page is also returned for example when the header size is too large:
INFO: Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Request header is too large
Is it possible to have a custom error page for those errors? More generally for when Tomcat triggers this HTTP 400 response. Delivering an empty response is the worst UX. I am aware that the creation of such requests should be avoided, but I am nonetheless looking for a fallback.
I have set up a custom error page in my (embedded) Tomcat context with ctx.addErrorPage(...) for the error code 400.
It works properly when triggered from my webapp.
E.g. when delegating the error handling to the servlet error handling mechanism with res.sendError(SC_BAD_REQUEST); - res being a HttpServletResponse.
Unfortunately for the kind of tomcat errors described at the top, the custom error page is not used.
Thanks!
This is a nuisance to me as well. Unfortunately, from having a look at the sources, it seems to be wired deep in Tomcat's internals, and can't be changed easily.
In particular, the exceptions you note are thrown in org.apache.coyote.http11.Http11InputBuffer, which is part of one of Tomcat's component called the Coyote HTTP/1.1 Connector (old docs, newer docs don't have this):
The Coyote HTTP/1.1 Connector element represents a Connector component
that supports the HTTP/1.1 protocol. It enables Catalina to function
as a stand-alone web server, in addition to its ability to execute
servlets and JSP pages.
Also, the exceptions end up in catalina.log and are very short - compare this to when you get an exception from the JSP processor, which are several times that size.
So I think it isn't trivial to patch this - at least not without knowledge about Tomcat internals, which I don't have :(

Tomcat 6.0.36 not reporting why it responded with 400

I have a tomcat server and java client with java.net.HttpUrlConnection sending messages. Usually all works fine, but there some requests the client sends out which are responded with a 400 http error.
The problem is that nothing is shown on tomcat logs. I even tried to put .level=fine and other log level changes, and still no exception or error was shown.
I'm suspecting bad encoding in request or something like that, but tomcat doesn't give me any clues.
By the way, the URL is OK. I also see the request reaches the server but not to my servlet.
It appears tomcat gets the message, declares it bad and doesn't log what's wrong.
Can anybody think of a way to see the 400 reason?
Thank you
I finally figured out -
I saw that the size of the total headers + size of data written to OutputStream - was exceptionally high - and so I defined in the Tomcat HTTP connector:
Connector port="8080" protocol="HTTP 1/1" maxPostSize="10485760" maxHttpHeaderSize="10485760"/
It is a shame Tomcat doesn't just tell me this, and I had to guess my - I will report this as a bug.
Thank you
Indeed, this was also the solution to the "http 400 bad request" error on Internet Explorer 11.
Adding
maxHttpHeaderSize="10485760" maxPostSize="10485760"
to the Connector-node of Tomcat's server.xml.
Seems my ajax-request (extjs) on IE11 are using a bigger request header then the default (8192 = 8 KB) max http header size on Tomcat 6?
With IE10 and Chrome I didn't experience this problem.
This is a very nice issue to be discussed about. I also faced the same issue in my organization's work. I was clueless about it as there were no good logging about it in catalina.out or in our application logs. Http calls made from client apps to the API that was running in Tomcat_8 were getting rejected by the server with 400 bad request. Only Tomcat locahost_access logs records it by printing the 400 http status fro the request. After I increased the http header size the issue got resolved.

The https URL hostname does not match the Common Name (CN) on the server certificate

I am getting the following error
javax.xml.ws.soap.SOAPFaultException: Marshalling Error: The https URL hostname does not match the Common Name (CN) on the server certificate. To disable this check (NOT recommended for production) set the CXF client TLS configuration property "disableCNCheck" to true.
when I try to connect and use the Web Services.
I have added the following lines in cxf.xml but it still doesn't work.
<http-conf:conduit name="*.http-conduit">
<!-- deactivate HTTPS url hostname verification (localhost, etc)
WARNING ! disableCNcheck=true should NOT be used in production -->
<http-conf:tlsClientParameters disableCNCheck="true" />
The cxf.xml file is placed under WEB-INF/classes/CxfService.
Kindly let me know on what would be the issue?.
There may be no real issue with this configuration. The host name that you use in the URL to the web service does not match the host name in the certificate, but this might be for a number of legitimate reasons, while still allowing the access to the right data.
SSL provides two kind of protections.
Privacy: It provides an encrypted channel over which the data passes so that nobody else can see that data
Source Assurance: It also provides assurance that you are connected to site that you asked to be connected to.
You can then see three levels of security:
no protections at all
encrypted channel so nobody can see your data
encrypted channel, as well as assurance that you are connected to the site you expect to.
It is that latter function that you are disabling. The site provides an encrypted certificate that can be decoded to state the DNS name that was used to access the site. If the name you used, and the name in the certificate do not match, you get this warning. As you probably know, there are multiple ways to address a server, and the certificate only matches the one DNS name that the certificate is for. Perhaps you are not accessing the service with the correct name? Or possibly you have a "self-signed" service which offers the encrypted channel, but not the source assurance.
The question to ask yourself: are you worried that someone will hack the DNS system, and cause your request (by DNS name) to be routed to a server which then will serve up false data in place of the web service you expect. It certainly can happen, and I am not going to say that it never happens, but it is very rare. See more discussion of this.
That is the potential issue: someone may spoof the web service you are calling. The security experts will never recommend a compromise position, but you should assess the value of the data, the likelihood of a spoofed service, and the damage that such a spoofing would cause. If this is a significant problem, then you must use a hostname that matches the certificate, or you must get a certificate that matched the hostname that you use.

Categories