¿No permitir métodos HTTP en Tomcat distingue entre mayúsculas y minúsculas?

11

Puse lo siguiente en el web.xml de mi aplicación para intentar no permitir 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, entonces ahora:

Si hago una solicitud con el método de DELETE, obtengo un 403 de vuelta.

Si hago una solicitud con el método de delete, obtengo un 403 de vuelta.

PERO

Si hago una solicitud con el método de DeLeTeme sale bien!

¿Cómo puedo hacer que no permita estas mayúsculas y minúsculas?

Editar: lo estoy probando con un programa C #:

    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.Textes un cuadro de texto donde estoy escribiendo el nombre del método. Cuando hay un 403, se lanza una excepción que queda atrapada en el bloque catch.

Cache_test.jsp contiene:

<%
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());
%>
desarrolladorwjk
fuente
Cómo lo pruebas ?
Xavier Lucas
@XavierLucas, agregó eso a la pregunta
developerwjk
1
Su programa de prueba es defectuoso. HttpWebRequestse mayúsculas y minúsculas reconocer y convertir métodos HTTP estándar a mayúsculas. Además, se documenta que solo permite métodos HTTP estándar. La mejor opción es utilizar una secuencia TCP sin procesar (por ejemplo, en netcat, o PuTTY raw, o telnet, etc.).
Bob
1
@Bob, lo hice en .NET 2.0 en Visual C # 2005 Express y no encontré ninguno de esos problemas. Está enviando exactamente lo que escribo. Entonces deben haber cambiado eso en una versión posterior.
developerwjk
1
@Bob, Lol. La documentación de Microsoft es incorrecta / engañosa. Para la versión .NET 2.0 también dicen "La propiedad Método se puede establecer en cualquiera de los verbos del protocolo HTTP 1.1: OBTENER, ENCABEZAR, PUBLICAR, PONER, ELIMINAR, RASTREAR u OPCIONES". Pero no se limita a eso de ninguna manera en la práctica.
developerwjk

Respuestas:

13

Independientemente del comportamiento incorrecto de Tomcat con respecto al estándar HTTP, debe usar una lista blanca para permitir métodos específicos en lugar de una lista negra.

Por ejemplo, la siguiente lista blanca bloqueará todos los métodos, excepto los que distinguen entre mayúsculas GET y minúsculas y 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>

(Nota: requiere Tomcat 7+. Aquellos que usen versiones anteriores tendrán que investigar otras soluciones, por ejemplo, un filtro de servlet).

Árbitro

Beto
fuente
Cuando hago eso con POST también incluido, voy a una página en el sitio (simplemente haciendo clic en un enlace o marcador) y me da un 405.
developerwjk
En realidad me da HTTP Status 403 - El acceso al recurso solicitado se le ha denegado
developerwjk
Lo probé en el servidor web.xml, e ignoró las omisiones y simplemente bloqueó todo. Tomó eso. Lo probé en el archivo web.xml de la aplicación, y nuevamente, solo está bloqueando todos los métodos e ignorando las omisiones.
developerwjk
También probé exactamente como se indicó anteriormente, pero sacando <auth-constraint />y luego simplemente permite todo.
developerwjk
2
@developerwjk http-method-omissionse definió por primera vez en Servlet API 3.0, implementado por Tomcat 7+: tomcat.apache.org/whichversion.html . Desafortunadamente, esto significa que esto no funcionará en Tomcat 6 y versiones anteriores (nota: 5 ya es EOL). Puede probar la otra solución propuesta en la pregunta SO vinculada que recomienda establecer dos security-constraints separadas . No pude confirmar que una funcione en 7, por lo que no la incluí en esta respuesta.
Bob
13

Bueno, después de realizar pruebas rápidas en algunos servidores aleatorios con Server: Apache-Coyottefirma de encabezado en sus respuestas HTTP, parece que tiene razón, ya que el envío get / HTTP/1.1\r\nHost: <target_IP>\r\n\r\ncon una conexión netcat simple funcionó cada vez que se debería haber recibido un código 400 HTTP.

Por ejemplo :

$ { 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.@[email protected].......
..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

Debo decir que estoy un poco sorprendido aquí y no me sorprendería ver que ese comportamiento se extendió a todos los métodos HTTP / 1.1 en tal caso.

Debe completar un informe de errores en su herramienta de seguimiento de errores y enviar un correo electrónico a la lista de correo apropiada porque es una violación fea del RFC 2616 (ver más abajo) con malas consecuencias.

5.1.1 Método

  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
Xavier Lucas
fuente
3
Nota: RFC 2616 ahora se reemplaza por RFC 7230-7235. RFC 7230 § 3.1.1 : "El método de solicitud distingue entre mayúsculas y minúsculas". RFC 7231 § 4 : "Por convención, los métodos estandarizados se definen en letras mayúsculas US-ASCII", seguidos de la misma lista en su respuesta.
Bob
1
El código de estado de respuesta debería ser 405 Método no permitido.
Lie Ryan
3
@LieRyan No porque eso significaría que el token del método se ajusta al RFC mientras que el servidor no permite que se use en este recurso. RFC 2616 § 10.4.1: [400 Solicitud incorrecta] El servidor no pudo entender la solicitud debido a una sintaxis incorrecta. RFC 2616 § 10.4.6 [Método 405 no permitido] El método especificado en la línea de solicitud no está permitido para el recurso identificado por el URI de solicitud. El token getno es un método HTTP de ninguna manera (vea el extracto de RFC 2616 § 5.1.1 arriba)
Xavier Lucas
@XavierLucas: el uso del método de minúsculas no es un error de sintaxis, consulte la Sección 5 del RFC2616 . En el ABNF, extension-methodtenga una sintaxis tokenque incluya todos los caracteres alfanuméricos y algunos símbolos, no solo los métodos enumerados específicamente en el RFC. Casi todas las partes de HTTP son extensibles, siempre que el cliente y el servidor acuerden cómo se extenderán, incluida la definición de sus propios métodos en minúsculas. La línea de solicitud "get / HTTP / 1.1" está sintácticamente bien, solo viola el RFC en ese nombre de método que distingue entre mayúsculas y minúsculas.
Lie Ryan
@LieRyan The extension-methodestá aquí para dejar la puerta abierta a los próximos RFC, no está aquí para agregar sus propios métodos fuera del alcance de RFC y pretender que está ejecutando servicios compatibles con HTTP / 1.1. Por lo tanto, se debe devolver un 400 porque aún no ha aparecido dicho método en la última RFC, por lo que hoy es un token no válido. Si el token era válido con respecto a la lista de métodos actual e implementado en el lado del servidor, pero no estaba permitido, se debería devolver un 405. Se debe devolver un 501 en caso de que el método sea válido pero no esté implementado en el lado del servidor.
Xavier Lucas