A proibição de métodos HTTP no Tomcat diferencia maiúsculas de minúsculas?

11

Coloquei o seguinte no web.xml do meu aplicativo para tentar desabilitar 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, agora:

Se eu fizer uma solicitação com o método de DELETEeu recebo um 403 de volta.

Se eu fizer uma solicitação com o método de deleteeu recebo um 403 de volta.

MAS

Se eu fizer uma solicitação com o método de DeLeTeeu fico OK!

Como posso impedir que esses casos não façam diferença?

Edit: Estou testando-o com um 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.Texté uma caixa de texto onde estou digitando o nome do método. Quando existe um 403, é lançada uma exceção que é capturada no bloco de captura.

O cache_test.jsp contém:

<%
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());
%>
developerwjk
fonte
Como você testá-lo?
Xavier Lucas
@XavierLucas, Adicionado à pergunta
developerwjk
1
Seu programa de teste é falho. HttpWebRequestvai diferenciar maiúsculas de minúsculas reconhecer e converter métodos HTTP padrão para maiúsculas. Além disso, está documentado como permitindo apenas métodos HTTP padrão. A melhor opção é usar um fluxo TCP bruto (por exemplo, em netcat, PuTTY raw ou telnet, etc.).
Bob
1
@ Bob, eu fiz isso no .NET 2.0 no Visual C # 2005 Express e não tive nenhum desses problemas. Está enviando exatamente o que eu digito. Então eles devem ter mudado isso em uma versão posterior.
developerwjk
1
@ Bob, lol. A documentação da Microsoft está errada / enganosa. Para a versão .NET 2.0, eles também dizem "A propriedade Method pode ser definida como qualquer um dos verbos do protocolo HTTP 1.1: GET, HEAD, POST, PUT, DELETE, TRACE ou OPTIONS". Mas não se restringe a isso de forma alguma na prática.
Developerwjk

Respostas:

13

Independentemente do comportamento incorreto do Tomcat em relação ao padrão HTTP, você deve usar uma lista de permissões para permitir métodos específicos, em vez de uma lista negra.

Por exemplo, a lista de permissões a seguir bloqueará todos os métodos, exceto os que diferenciam maiúsculas de minúsculas GET e 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: requer Tomcat 7+. Os usuários de versões mais antigas precisarão investigar outras soluções, por exemplo, um filtro de servlet.)

Ref.

Prumo
fonte
Quando faço isso com POST também incluiu, eu ir para uma página no site (basta clicar em um link ou atalho para ele) e ele me dá um 405.
developerwjk
Na verdade, ele me fornece o status HTTP 403 - O acesso ao recurso solicitado foi negado #
developerwjk
Eu tentei no web.xml do servidor e ignorou as omissões e apenas bloqueou tudo. Tirou isso. Tentei no web.xml do aplicativo e, novamente, está apenas bloqueando todos os métodos e ignorando as omissões.
developerwjk
Também tentei exatamente como acima, mas tirando <auth-constraint />e, em seguida, apenas permite tudo.
developerwjk
2
O @developerwjk http-method-omissionfoi definido pela primeira vez na API do Servlet 3.0, implementada pelo Tomcat 7+: tomcat.apache.org/whichversion.html . Infelizmente, isso significa que isso não funcionará no Tomcat 6 e mais antigo (nota: 5 já é EOL). Você pode tentar a outra solução proposta na pergunta SO vinculada que recomenda definir dois security-constraints separados - não pude confirmar se um funciona em 7, portanto não o incluí nesta resposta.
Bob
13

Bem, após testes rápidos em alguns servidores aleatórios com a Server: Apache-Coyotteassinatura do cabeçalho em suas respostas HTTP, parece que você está certo, pois o envio get / HTTP/1.1\r\nHost: <target_IP>\r\n\r\ncom uma conexão netcat simples funcionava sempre que um código HTTP 400 deveria ter sido recebido.

Por exemplo :

$ { 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

Devo dizer que estou um pouco chocado aqui e não ficaria surpreso ao ver esse comportamento estendido a todos os métodos HTTP / 1.1 nesse caso.

Você deve preencher um relatório de bug na ferramenta de rastreamento de bugs e enviar um email para a lista de discussão apropriada, pois essa é uma violação feia da RFC 2616 (veja abaixo) com más conseqüências.

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
fonte
3
Nota: O RFC 2616 agora é substituído pelo RFC 7230-7235. RFC 7230 § 3.1.1 : "O método de solicitação diferencia maiúsculas de minúsculas". RFC 7231 § 4 : "Por convenção, os métodos padronizados são definidos em letras US-ASCII com todas as letras maiúsculas.", Seguido pela mesma lista na sua resposta.
Bob
1
O código de status da resposta deve realmente ser 405 Método não permitido.
Lie Ryan
3
@LieRyan Não, porque isso significaria que o token de método se ajusta ao RFC enquanto o servidor não permite que ele seja usado nesse recurso. RFC 2616 § 10.4.1: [400 Solicitação incorreta ] A solicitação não pôde ser entendida pelo servidor devido à sintaxe malformada. RFC 2616 § 10.4.6 [405 Método não permitido] O método especificado na linha de solicitação não é permitido para o recurso identificado pelo URI da solicitação. O token getnão é um HTTP método de qualquer maneira (veja o trecho da RFC 2616 § 5.1.1 acima)
Xavier Lucas
@ XavierLucas: usar o método de letras minúsculas não é um erro de sintaxe, verifique a Seção 5 da RFC2616 . No ABNF, extension-methodtenha uma sintaxe tokenque inclua todos os caracteres alfanuméricos e alguns símbolos, não apenas os métodos listados especificamente na RFC. Quase todas as partes do HTTP são extensíveis, desde que o cliente e o servidor concordem como eles também devem ser estendidos, incluindo a definição de seus próprios métodos em minúsculas. A linha de solicitação "get / HTTP / 1.1" está sintaticamente correta, apenas viola a RFC no nome do método que diferencia maiúsculas de minúsculas.
Lie Ryan
@LieRyan extension-methodEstá aqui para deixar a porta aberta para as próximas RFCs, que não estão aqui para adicionar seus próprios métodos fora do escopo da RFC e fingir que você está executando serviços compatíveis com HTTP / 1.1. Portanto, um 400 deve ser retornado porque esse método ainda não apareceu na RFC mais recente, portanto, hoje é um token inválido. Se o token era válido em relação à lista de métodos atual e implementado no lado do servidor, mas não permitido, um 405 deve ser retornado. Um 501 deve ser retornado caso o método seja válido, mas não implementado no servidor.
Xavier Lucas