sequência de escape dupla dentro de um url: o módulo de filtragem de solicitação está configurado para negar uma solicitação que contém uma sequência de escape dupla

86

Em meu aplicativo ASP.NET MVC, estou tentando implementar uma URL como abaixo:

/ product / tags / para + famílias

Quando tento executar meu aplicativo com as configurações padrão, recebo esta mensagem com Código de Resposta 404.11:

Erro HTTP 404.11 - não encontrado

O módulo de filtragem de solicitações está configurado para negar uma solicitação que contenha uma sequência de escape dupla.

Posso contornar esse erro implementando o código abaixo dentro do meu web.config:

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>

Então, agora eu não estou recebendo nenhum 404.11.

O que estou me perguntando é que tipo de brechas de segurança estou abrindo com essa implementação.

BTW, meu aplicativo está em .Net Framework 4.0funcionamento IIS 7.5.

tugberk
fonte
É possível chegar ao recurso desejado usando em seu /product/tags/for%20familieslugar? Então você tem uma solução alternativa para ids contendo espaços. Ou estou completamente perdido aqui?
Anders Tornblad,
@atornblad um pouco estranho, eu acho. Minha pergunta: o que me pergunto é que tipo de brechas de segurança estou abrindo com esta implementação.
tugberk
5
O IIS está apresentando o caractere "+", que é o comportamento padrão da Microsoft.
Todd Shelton,

Respostas:

57

As brechas de segurança que você pode abrir têm a ver com injeção de código - injeção de HTML, injeção de JavaScript ou injeção de SQL.

As configurações padrão protegem você de ataques de forma semi-eficiente, não permitindo que estratégias de injeção comuns funcionem. Quanto mais segurança padrão você remover, mais terá que pensar sobre o que fazer com a entrada fornecida por meio de URLs, strings de consulta de solicitação GET, dados de solicitação POST, cabeçalhos HTTP e assim por diante ...

Por exemplo, se você estiver criando consultas SQL dinâmicas com base no idparâmetro do seu método de ação, como este:

public ActionResult Tags(string id)
{
    var sql = "SELECT * FROM Tags Where tagName = '" + id + "'";
    // DO STUFF...
}

(... o que NÃO é uma boa ideia), a proteção padrão, implementada pelo .NET framework, pode interromper alguns dos cenários mais perigosos, como o usuário solicitando este URL:

/product/tags/1%27;drop%20table%20Tags;%20--

A ideia é tratar cada parte dos urls e outras entradas para os métodos de ação como possíveis ameaças. A configuração de segurança padrão fornece alguma proteção para você. Cada configuração de segurança padrão que você altera abre para um pouco mais de maldade potencial que você precisa lidar manualmente.

Presumo que você não esteja criando consultas SQL dessa maneira. Mas as coisas mais sorrateiras surgem quando você armazena a entrada do usuário em seu banco de dados e, em seguida, exibe-as. O usuário malévolo pode armazenar JavaScript ou HTML em seu banco de dados que sai não codificado, o que por sua vez ameaçaria outros usuários de seu sistema.

Anders Tornblad
fonte
6

Risco de segurança

A configuração allowDoubleEscapingse aplica apenas ao path(cs-uri-stem) e é melhor explicada por OWASP Double Encoding . A técnica é usada para contornar os controles de segurança, codificando a URL da solicitação duas vezes. Usando seu URL como exemplo:

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies

Suponha que existam controles de segurança especificamente para /product/tags/for+families. Chega uma solicitação com /product/tags/for%252Bfamilieso mesmo recurso, embora não seja verificada pelos controles de segurança mencionados. Usei o termo generalizado de controles de segurança porque eles podem ser qualquer coisa, como exigir um usuário autenticado, verificar o SQLi etc.

Por que o IIS bloqueia?

O sinal de mais (+) é um caractere reservado de acordo com RFC2396 :

Muitos URI incluem componentes que consistem em ou são delimitados por determinados caracteres especiais. Esses caracteres são chamados de "reservados", pois seu uso no componente URI é limitado ao seu propósito reservado. Se os dados de um componente URI entrarem em conflito com a finalidade reservada, os dados conflitantes devem ser escapados antes de formar o URI.

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

Wade Hilmo tem uma excelente postagem intitulada Como o IIS bloqueia caracteres em URLs . São fornecidas muitas informações e antecedentes. A parte específica para o sinal de mais é a seguinte:

Portanto, allowDoubleEscaping / VerifyNormalization parece bastante simples. Por que eu disse que causa confusão? O problema é quando um caractere '+' aparece em um URL. O caractere '+' não parece ter escape, pois não envolve um '%'. Além disso, o RFC 2396 o indica como um caractere reservado que pode ser incluído em uma URL quando está em forma de escape (% 2b). Mas com allowDoubleEscaping definido com seu valor padrão false, vamos bloqueá-lo mesmo na forma de escape. A razão para isso é histórica: nos primeiros dias do HTTP, um caractere '+' era considerado uma abreviação para um caractere de espaço. Alguns canonicalizadores, quando recebem um URL que contém um '+', o convertem em um espaço. Por esse motivo, consideramos um '+' não canônico em um URL. Não consegui encontrar nenhuma referência a um RFC que indique este tratamento '+',

Por experiência própria, sei que, quando o IIS registra uma solicitação, os espaços são substituídos por um sinal de mais. Ter um sinal de mais no nome pode causar confusão ao analisar os logs.

Solução

Existem três maneiras de corrigir isso e duas maneiras de usar o sinal de mais.

  1. allowDoubleEscaping=true- Isso permitirá o escape duplo para todo o seu site / aplicativo. Dependendo do conteúdo, isso pode ser indesejável, para dizer o mínimo. O seguinte comando será definido allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- A Filtragem de solicitações oferece uma abordagem de lista de permissões. Ao adicionar esse caminho de URL a alwaysAllowedUrls, a solicitação não será verificada por nenhuma outra configuração de Filtragem de Solicitação e continuará no pipeline de solicitação do IIS. A preocupação aqui é que a Filtragem de Solicitações não verificará a solicitação de:

    • Limites de solicitação: maxContentLength, maxUrl, maxQueryString
    • Verbos
    • Consulta - os parâmetros da string de consulta não serão verificados
    • Fuga dupla
    • Personagens de bit alto
    • Solicitar regras de filtragem
    • Solicitar limites de cabeçalho

    O comando a seguir será adicionado /product/tags/for+familiesao alwaysAllowedUrlssite padrão.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. Renomear - sim, apenas renomeie o arquivo / pasta / controlador / etc. se possível. Esta é a solução mais fácil.

user2320464
fonte
Para allowDoubleEscaping durante o desenvolvimento com IIS Express, aqui está o que fiz: stackoverflow.com/q/56463044/381082
DeveloperDan
3

Eu fiz um arround de trabalho para isso. então, quando você quiser colocar a string criptografada dentro da url para (IIS), você tem que limpar a sujeira: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; e quando você quiser decriptá-lo e usá-lo novamente, você deve sujá-lo novamente antes de decriptá-lo (para obter o resultado desejado).

Aqui está o meu código, espero que ajude alguém:

 public static string cleanUpEncription(string encriptedstring)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m","s1l2a3s4h","q1e2st3i4o5n" ,"T22p14nt2s", "a9t" , "a2n3nd","e1q2ua88l","p22l33u1ws","d0l1ar5","c0m8a1a"};

            foreach (string dirtyCharacter in dirtyCharacters)
            {
                encriptedstring=encriptedstring.Replace(dirtyCharacter, cleanCharacters[Array.IndexOf(dirtyCharacters, dirtyCharacter)]);
            }
            return encriptedstring;
        }

        public static string MakeItDirtyAgain(string encriptedString)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m", "s1l2a3s4h", "q1e2st3i4o5n", "T22p14nt2s", "a9t", "a2n3nd", "e1q2ua88l", "p22l33u1ws", "d0l1ar5", "c0m8a1a" };
            foreach (string symbol in cleanCharacters)
            {
                encriptedString = encriptedString.Replace(symbol, dirtyCharacters[Array.IndexOf(cleanCharacters,symbol)]);
            }
            return encriptedString;
        }
Mark Dibeh
fonte
O que é pntGlm?
StuperUser
@StuperUser apenas caracteres aleatórios
Mark Dibeh
1
A string deve ser base64codificada em vez de usar essa técnica de substituição. Por exemplo, a autenticação básica usa base64para codificar as credenciais enviadas, pois pode conter caracteres especiais / reservados.
user2320464
problema com base64 é / é um caractere de base64 e pode quebrar as rotas
Garr Godfrey
1

Então me deparei com isso quando estava chamando uma API de um aplicativo MVC. Em vez de abrir a brecha de segurança, modifiquei meu caminho.

Em primeiro lugar, eu recomendo NÃO desabilitar essa configuração. É mais apropriado modificar o design da aplicação / recurso (por exemplo, codificar o caminho, passar os dados em um cabeçalho ou no corpo).

Embora esta seja uma postagem mais antiga, pensei em compartilhar como você pode resolver esse erro se estiver recebendo isso de uma chamada para uma API usando o método HttpUtility.UrlPathEncode em System.Web .

Eu uso RestSharp para fazer chamadas, então meu exemplo é usar RestRequest:

var tags = new[] { "for", "family" };
var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}");

Isso produz um caminho igual a:

/ product / tags / para% 2Bfamílias

Por outro lado, NÃO crie uma consulta dinâmica com base nas entradas de um usuário. Você DEVE sempre usar um SqlParameter . Além disso, é extremamente importante do ponto de vista da segurança retornar os valores com a codificação apropriada para evitar ataques de injeção.

~ Saúde

Rogala
fonte
0

Codifique a string criptografada separada:

return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes("string"));

Decodifique a string criptografada separada:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
incomum
fonte