12

I have put the following in the web.xml of my application to attempt to disallow PUT, DELETE, etc.:

 <security-constraint>
 <web-resource-collection>
  <web-resource-name>restricted methods</web-resource-name>
  <url-pattern>/*</url-pattern>
  <http-method>DELETE</http-method>
  <http-method>PUT</http-method>
  <http-method>SEARCH</http-method>
  <http-method>COPY</http-method>
  <http-method>MOVE</http-method>
  <http-method>PROPFIND</http-method>
  <http-method>PROPPATCH</http-method>
  <http-method>MKCOL</http-method>
  <http-method>LOCK</http-method>
  <http-method>UNLOCK</http-method>
  <http-method>delete</http-method>
  <http-method>put</http-method>
  <http-method>search</http-method>
  <http-method>copy</http-method>
  <http-method>move</http-method>
  <http-method>propfind</http-method>
  <http-method>proppatch</http-method>
  <http-method>mkcol</http-method>
  <http-method>lock</http-method>
  <http-method>unlock</http-method>
 </web-resource-collection>
 <auth-constraint />
 </security-constraint>

Ok, so now:

If I do a request with method of DELETE I get a 403 back.

If I do a request with method of delete I get a 403 back.

BUT

If I do a request with method of DeLeTe I get OK!

How can I make it disallow these case-insensitive?

Edit: I'm testing it with a C# program:

    private void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = "making request";
        System.Threading.Thread.Sleep(400);
        WebRequest req = WebRequest.Create("http://serverurl/Application/cache_test.jsp");
        req.Method = txtMethod.Text;
        try
        {
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

            textBox1.Text = "Status: " + resp.StatusCode;

            if (resp.StatusCode == System.Net.HttpStatusCode.OK)
            {
                WebHeaderCollection header = resp.Headers;
                using (System.IO.StreamReader reader = new System.IO.StreamReader(resp.GetResponseStream(), ASCIIEncoding.ASCII))
                {
                    //string responseText = reader.ReadToEnd();
                    textBox1.Text += "\r\n" + reader.ReadToEnd();
                }
            }
        }
        catch (Exception ex)
        {
            textBox1.Text = ex.Message;
        }
    }

txtMethod.Text is a text box where I'm typing the method name. When there is a 403 an exception is thrown which is caught in the catch block.

The cache_test.jsp contains:

<%
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma","no-cache");

out.print("Method used was: "+request.getMethod());
%>
5
  • How do you test it ? – Xavier Lucas Jan 26 '15 at 23:20
  • @XavierLucas, Added that to the question – developerwjk Jan 26 '15 at 23:31
  • 1
    Your test program is flawed. HttpWebRequest will case-insensitively recognise and convert standard HTTP methods to uppercase. Additionally, it is documented as only allowing standard HTTP methods. The best option is to use a raw TCP stream (e.g. in netcat, or PuTTY raw, or telnet, etc.). – Bob Jan 27 '15 at 23:54
  • 1
    @Bob, I did it in .NET 2.0 in Visual C# 2005 Express and didn't run into any of those issues. It is sending exactly what I type. So they must have changed that in a later version. – developerwjk Jan 28 '15 at 20:21
  • 1
    @Bob, Lol. Microsoft's documentation is wrong/misleading. For the .NET 2.0 version they also say "The Method property can be set to any of the HTTP 1.1 protocol verbs: GET, HEAD, POST, PUT, DELETE, TRACE, or OPTIONS." But it doesn't restrict to that in any way in practice. – developerwjk Jan 28 '15 at 20:23
14

Regardless of Tomcat's incorrect behaviour with regards to the HTTP standard, you should be using a whitelist to allow specific methods rather than a blacklist.

For example, the following whitelist will block all methods except the case-sensitive GET and HEAD.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>restricted methods</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method-omission>GET</http-method-omission>
        <http-method-omission>HEAD</http-method-omission>
    </web-resource-collection>
    <auth-constraint />
</security-constraint>

(Note: requires Tomcat 7+. Those using older versions will have to investigate other solutions, e.g. a servlet filter.)

Ref

8
  • When I do that with POST also included, I go to a page on the site (just clicking a link or bookmark to it) and it gives me a 405. – developerwjk Jan 27 '15 at 17:47
  • Actually it gives me HTTP Status 403 - Access to the requested resource has been denied – developerwjk Jan 27 '15 at 17:51
  • I've tried it in the server's web.xml, and it ignored the omissions and just blocked everything. Took that out. Tried it in the application's web.xml, and again, its just blocking every method and ignoring the omissions. – developerwjk Jan 27 '15 at 18:02
  • Also tried exactly as above but taking out <auth-constraint /> and then it just allows everything. – developerwjk Jan 27 '15 at 18:10
  • 2
    @developerwjk http-method-omission was first defined in in Servlet API 3.0, which is implemented by Tomcat 7+: tomcat.apache.org/whichversion.html. Unfortunately, this means this won't work in Tomcat 6 and older (note: 5 is EOL already). You can try the other proposed solution in the linked SO question that recommends setting two separate security-constraints - I could not confirm that one works in 7, so did not include it in this answer. – Bob Jan 27 '15 at 22:22
13

Well, after quick testing over some random servers holding Server: Apache-Coyotte header signature in their HTTP replies, it seems you are right as sending get / HTTP/1.1\r\nHost: <target_IP>\r\n\r\n with a simple netcat connection worked every time while a 400 HTTP code should have been received.

For instance :

$ { echo -en "get / HTTP/1.1\r\nHost: <target_IP>:8080\r\n\r\n" ; } | nc <target_IP> 8080

01:14:58.095547 IP 192.168.1.3.57245 > <target_IP>.8080: Flags [P.], seq 1:42, ack 1, win 115, options [nop,nop,TS val 4294788321 ecr 0], length 41
E..]C.@.@..Y......p.....A..v.......s.......
..D.....get / HTTP/1.1
Host: <target_IP>:8080

[...]

01:14:58.447946 IP <target_IP>.8080 > 192.168.1.3.57245: Flags [.], seq 1:1409, ack 43, win 65494, options [nop,nop,TS val 7981294 ecr 4294787971], length 1408
E...f...i.....p.............A..............
.y....C.HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Transfer-Encoding: chunked
Date: Tue, 27 Jan 2015 00:15:14 GMT

I must say I'm a bit shocked here and I would not be surprised to see that behaviour extended to all HTTP/1.1 methods in such case.

You should fill a bug report on their bug tracking tool and send a mail to the appropriate mailing list because that's one ugly violation of RFC 2616 (see below) with bad consequences.

5.1.1 Method

  The Method  token indicates the method to be performed on the
  resource identified by the Request-URI. The method is case-sensitive.

      Method         = "OPTIONS"                ; Section 9.2
                     | "GET"                    ; Section 9.3
                     | "HEAD"                   ; Section 9.4
                     | "POST"                   ; Section 9.5
                     | "PUT"                    ; Section 9.6
                     | "DELETE"                 ; Section 9.7
                     | "TRACE"                  ; Section 9.8
                     | "CONNECT"                ; Section 9.9
                     | extension-method
      extension-method = token
7
  • 3
    Note: RFC 2616 is now replaced by RFC 7230-7235. RFC 7230 § 3.1.1: "The request method is case-sensitive." RFC 7231 § 4: "By convention, standardized methods are defined in all-uppercase US-ASCII letters.", followed by the same list in your answer. – Bob Jan 27 '15 at 4:00
  • 1
    The response status code should actually be 405 Method Not Allowed. – Lie Ryan Jan 27 '15 at 11:43
  • 3
    @LieRyan No because that would mean the method token fits the RFC while the server doesn't allow it to be used on this resource. RFC 2616 § 10.4.1 : [400 Bad Request] The request could not be understood by the server due to malformed syntax. RFC 2616 § 10.4.6 [405 Method Not Allowed] The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The token get is not an HTTP method in any way (see the excerpt of RFC 2616 § 5.1.1 above) – Xavier Lucas Jan 27 '15 at 12:04
  • @XavierLucas: using lower case method isn't a syntax error, check the RFC2616 Section 5. In the ABNF, extension-method have syntax token which includes all alphanumeric characters and some symbols, not just the methods specifically listed in the RFC. Almost every part of HTTP is extensible, as long as both client and server agree how they are too be extended, including defining your own lower case methods. The request line "get / HTTP/1.1" is syntactically fine, it just violates the RFC in that method name should be case sensitive. – Lie Ryan Jan 27 '15 at 12:22
  • @LieRyan The extension-method is here to leave the door open to next RFCs, that's not here to get your own methods added out of RFC's scope and pretend that you are running HTTP/1.1 compliant services. So a 400 should be returned because no such method have appeared yet in latest RFC thus that's, today, an invalid token. If the token was valid regarding the current method list and implemented server-side but disallowed then a 405 should be returned. A 501 should be returned in case the method is valid but not implemented server-side. – Xavier Lucas Jan 27 '15 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.