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 ? Jan 26, 2015 at 23:20
  • @XavierLucas, Added that to the question Jan 26, 2015 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, 2015 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. Jan 28, 2015 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. Jan 28, 2015 at 20:23

2 Answers 2

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. Jan 27, 2015 at 17:47
  • Actually it gives me HTTP Status 403 - Access to the requested resource has been denied Jan 27, 2015 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. Jan 27, 2015 at 18:02
  • Also tried exactly as above but taking out <auth-constraint /> and then it just allows everything. Jan 27, 2015 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, 2015 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, 2015 at 4:00
  • 1
    The response status code should actually be 405 Method Not Allowed.
    – Lie Ryan
    Jan 27, 2015 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) Jan 27, 2015 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, 2015 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. Jan 27, 2015 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.