Secuencia de escape doble dentro de una URL: el módulo de filtrado de solicitudes está configurado para rechazar una solicitud que contiene una secuencia de escape doble.

86

En mi aplicación ASP.NET MVC, estoy tratando de implementar una URL como la siguiente:

/ producto / etiquetas / para + familias

Cuando intento ejecutar mi aplicación con las configuraciones predeterminadas, recibo este mensaje con el código de respuesta 404.11:

Error HTTP 404.11: no encontrado

El módulo de filtrado de solicitudes está configurado para rechazar una solicitud que contiene una secuencia de escape doble.

Puedo solucionar este error implementando el siguiente código dentro de mi web.config:

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

Entonces, ahora no obtengo ninguno 404.11.

Lo que me pregunto es qué tipo de agujeros de seguridad estoy abriendo con esta implementación.

Por cierto, mi aplicación está .Net Framework 4.0funcionando y funcionando IIS 7.5.

tugberk
fuente
¿Es posible alcanzar el recurso deseado utilizando en su /product/tags/for%20familieslugar? Entonces tiene una solución para los identificadores que contienen espacios. ¿O estoy completamente fuera de aquí?
Anders Tornblad
@atornblad un poco fuera, supongo. Mi pregunta: Lo que me pregunto es qué tipo de agujeros de seguridad estoy abriendo con esta implementación.
tugberk
5
IIS lanza el carácter "+", que es el comportamiento predeterminado de Microsoft.
Todd Shelton

Respuestas:

57

Los agujeros de seguridad que puede abrir tienen que ver con la inyección de código: inyección HTML, inyección JavaScript o inyección SQL.

La configuración predeterminada lo protege de los ataques de manera semi-eficiente al no permitir que funcionen las estrategias de inyección comunes. Cuanta más seguridad predeterminada elimine, más tendrá que pensar en lo que hace con la entrada proporcionada a través de URL, cadenas de consulta de solicitud GET, datos de solicitud POST, encabezados HTTP, etc.

Por ejemplo, si está creando consultas SQL dinámicas basadas en el idparámetro de su método de acción, como este:

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

(... lo cual NO es una buena idea), la protección predeterminada, implementada por .NET framework, podría detener algunos de los escenarios más peligrosos, como el usuario que solicita esta URL:

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

La idea es tratar cada parte de las URL y otras entradas a los métodos de acción como posibles amenazas. La configuración de seguridad predeterminada le proporciona algo de esa protección. Cada configuración de seguridad predeterminada que cambie se abre para un poco más de daño potencial que debe manejar manualmente.

Supongo que no está creando consultas SQL de esta manera. Pero las cosas más disimuladas vienen cuando almacena la entrada del usuario en su base de datos y luego la muestra. El usuario malévolo podría almacenar JavaScript o HTML en su base de datos sin codificar, lo que a su vez amenazaría a otros usuarios de su sistema.

Anders Tornblad
fuente
6

Riesgo de seguridad

La configuración allowDoubleEscapingsolo se aplica a path(cs-uri-stem) y se explica mejor mediante la codificación doble OWASP . La técnica se utiliza para sortear los controles de seguridad mediante la codificación URL de la solicitud dos veces. Usando su URL como ejemplo:

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

Supongamos que existen controles de seguridad específicos para /product/tags/for+families. Llega una solicitud para el /product/tags/for%252Bfamiliesque es el mismo recurso, aunque los controles de seguridad mencionados anteriormente no la controlan. Usé el término generalizado de controles de seguridad porque podrían ser cualquier cosa, como requerir un usuario autenticado, verificar SQLi, etc.

¿Por qué se bloquea IIS?

El signo más (+) es un carácter reservado por RFC2396 :

Muchos URI incluyen componentes que consisten en, o delimitados por, ciertos caracteres especiales. Estos caracteres se denominan "reservados", ya que su uso dentro del componente URI se limita a su propósito reservado. Si los datos de un componente de URI entran en conflicto con el propósito reservado, entonces los datos en conflicto deben escaparse antes de formar el URI.

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

Wade Hilmo tiene una publicación excelente titulada Cómo IIS bloquea caracteres en URL . Se proporciona mucha información y antecedentes. La parte específica para el signo más es la siguiente:

Así que allowDoubleEscaping / VerifyNormalization parece bastante sencillo. ¿Por qué dije que causa confusión? El problema es cuando aparece un carácter '+' en una URL. El carácter '+' no parece escaparse, ya que no implica un '%'. Además, RFC 2396 lo señala como un carácter reservado que se puede incluir en una URL cuando está en formato de escape (% 2b). Pero con allowDoubleEscaping establecido en su valor predeterminado de falso, lo bloquearemos incluso en forma de escape. La razón de esto es histórica: en los primeros días de HTTP, un carácter '+' se consideraba una abreviatura de un carácter de espacio. Algunos canonicalizadores, cuando se les da una URL que contiene un '+' lo convertirán en un espacio. Por esta razón, consideramos que un '+' no es canónico en una URL. No pude encontrar ninguna referencia a un RFC que mencione este tratamiento '+',

Por mi propia experiencia, sé que cuando IIS registra una solicitud, los espacios se sustituyen por un signo más. Tener un signo más en el nombre puede causar confusión al analizar los registros.

Solución

Hay tres formas de solucionar este problema y dos formas de seguir utilizando el signo más.

  1. allowDoubleEscaping=true- Esto permitirá un doble escape para todo su sitio web / aplicación. Dependiendo del contenido, esto podría ser indeseable por decir lo menos. Se establecerá el siguiente comando allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- El filtrado de solicitudes ofrece un enfoque de lista blanca. Al agregar esa ruta de URL a alwaysAllowedUrls, la solicitud no será verificada por ninguna otra configuración de filtrado de solicitudes y continuará en la canalización de solicitudes de IIS. La preocupación aquí es que el filtrado de solicitudes no verificará la solicitud para:

    • Límites de solicitud: maxContentLength, maxUrl, maxQueryString
    • Verbos
    • Consulta: no se comprobarán los parámetros de la cadena de consulta
    • Doble escape
    • Personajes de High Bit
    • Solicitar reglas de filtrado
    • Solicitar límites de encabezado

    El siguiente comando se agregará /product/tags/for+familiesal alwaysAllowedUrlssitio web predeterminado.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. Cambiar nombre : sí, simplemente cambie el nombre del archivo / carpeta / controlador / etc. si es posible. Ésta es la solución más sencilla.

usuario2320464
fuente
Para permitir DoubleEscaping durante el desarrollo con IIS Express, esto es lo que hice: stackoverflow.com/q/56463044/381082
DeveloperDan
3

He hecho un trabajo para esto. así que cuando quieras poner la cadena encriptada dentro de la URL para (IIS) tienes que limpiarla de sucio: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; y cuando quiera describirlo y usarlo nuevamente, debe ensuciarlo nuevamente antes de describirlo (para obtener el resultado deseado).

Aquí está mi código, espero que ayude a alguien:

 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
fuente
¿Qué es pntGlm?
StuperUser
@StuperUser solo caracteres aleatorios
Mark Dibeh
1
La cadena debe estar base64codificada en lugar de utilizar esta técnica de sustitución. Por ejemplo, la autenticación básica se utiliza base64para codificar las credenciales enviadas, ya que puede contener caracteres especiales / reservados.
user2320464
problema con base64 es / es un carácter base64 y puede romper las rutas
Garr Godfrey
1

Así que me encontré con esto cuando estaba llamando a una API desde una aplicación MVC. En lugar de abrir el agujero de seguridad, modifiqué mi camino.

En primer lugar, recomiendo NO deshabilitar esta configuración. Es más apropiado modificar el diseño de la aplicación / recurso (por ejemplo, codificar la ruta, pasar los datos en un encabezado o en el cuerpo).

Aunque esta es una publicación anterior, pensé en compartir cómo podría resolver este error si recibe esto de una llamada a una API utilizando el método HttpUtility.UrlPathEncode en System.Web .

Uso RestSharp para hacer llamadas, por lo que mi ejemplo está usando RestRequest:

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

Esto produce una ruta igual a:

/ producto / etiquetas / para% 2Bfamilias

En otra nota, NO cree una consulta dinámica basada en las entradas de un usuario. Siempre DEBE usar un SqlParameter . Además, es extremadamente importante desde una perspectiva de seguridad devolver los valores con la codificación adecuada para evitar ataques de inyección.

~ Saludos

Rogala
fuente
0

Codifique la cadena cifrada separada:

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

Decodifica la cadena cifrada separada:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
unvascorriendo
fuente