URL-кодированная косая черта в URL-адресе

Моя карта:

routes.MapRoute(
   "Default",                                             // Route name
   "{controller}/{action}/{id}",                          // URL with params
   new { controller = "Home", action = "Index", id = "" } // Param defaults
);

Если я использую URL http://localhost:5000/Home/About/100%2f200, то нет соответствующего маршрута. Я изменяю URL-адрес на http://localhost:5000/Home/About/100, после чего маршрут снова сопоставляется.

Есть ли простой способ работы с параметрами, содержащими слэши? Другие escape-значения (пробел %20), похоже, работают.

EDIT:

Для кодирования Base64 работает для меня. Это делает URL уродливым, но пока что ОК.

public class UrlEncoder
{ 
    public string URLDecode(string  decode)
    {
        if (decode == null) return null;
        if (decode.StartsWith("="))
        {
            return FromBase64(decode.TrimStart('='));
        }
        else
        {
            return HttpUtility.UrlDecode( decode) ;
        }
    }

    public string UrlEncode(string encode)
    {
        if (encode == null) return null;
        string encoded = HttpUtility.PathEncode(encode);
        if (encoded.Replace("%20", "") == encode.Replace(" ", ""))
        {
            return encoded;
        }
        else
        {
            return "=" + ToBase64(encode);
        }
    }

    public string ToBase64(string encode)
    {
        Byte[] btByteArray = null;
        UTF8Encoding encoding = new UTF8Encoding();
        btByteArray = encoding.GetBytes(encode);
        string sResult = System.Convert.ToBase64String(btByteArray, 0, btByteArray.Length);
        sResult = sResult.Replace("+", "-").Replace("/", "_");
        return sResult;
    }

    public string FromBase64(string decode)
    {
        decode = decode.Replace("-", "+").Replace("_", "/");
        UTF8Encoding encoding = new UTF8Encoding();
        return encoding.GetString(Convert.FromBase64String(decode));
    }
}

EDIT1:

В конце концов оказалось, что лучший способ - сохранить красиво сформированную строку для каждого элемента, который мне нужно выбрать. Это намного лучше, потому что теперь я только кодирую значения и никогда их не расшифровываю. Все специальные символы становятся "-". У многих моих db-таблиц теперь есть дополнительный столбец "URL". Данные довольно стабильны, вот почему я могу идти этим путем. Я даже могу проверить, если данные в "URL" уникальны.

EDIT2:

Также следите за символом пробела. Он выглядит нормально на VS-интегрированном веб-сервере, но отличается от iis7 Правильно url кодирует символ пробела

Ответ 1

Если это только ваш последний параметр, вы можете сделать:

routes.MapRoute(
    "Default",                                                // Route name
    "{controller}/{action}/{*id}",                            // URL with parameters
    new { controller = "Home", action = "Index", id = "" });  // Parameter defaults

Ответ 2

В .NET 4.0 beta 2 команда CLR предложила обходное решение.

Добавьте это в свой файл web.config:

<uri> 
    <schemeSettings>
        <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
    </schemeSettings>
</uri>

Это приводит к тому, что класс Uri ведет себя в соответствии с RFC, описывающим URI, позволяя слэш-экранам сбежать на пути, не будучи неэкономным. Команда CLR сообщает, что они отклоняются от спецификации по соображениям безопасности, и установка этого в вашем файле .config в основном заставляет вас взять на себя ответственность за дополнительные соображения безопасности, связанные с не отменой косой черты.

Ответ 3

Здесь простое объяснение решения и суммирование того, что уже было сказано.

Сторона запроса:

  • UrlEncode ваш путь.
  • Замените '%' на '!'.
  • Сделайте запрос.

Сторона ответа:

  • Замените '!' с '%'.
  • UrlDecode ваш путь.
  • Используйте параметры, как они были предназначены.

Промойте, повторите, наслаждайтесь.

Ответ 4

Еще одна опция - использовать значение querystring. Очень хромой, но проще, чем пользовательская кодировка.

http://localhost:5000/Home/About?100%2f200

Ответ 5

То же самое для Java/Tomcat.

По-прежнему существует проблема, если у вас есть закодированный "/" (% 2F) в вашем URL-адресе.

RFC 3986 - В разделе 2.2 говорится: "Если данные для компонента URI будут конфликтуют с зарезервированным назначением символа в качестве разделителя, тогда конфликтующие данные должны быть закодированы до кодирования URI". (RFC 3986 - Раздел 2.2)

Но есть проблема с Tomcat:

http://tomcat.apache.org/security-6.html - Исправлено в Apache Tomcat 6.0.10

important: Обход каталога CVE-2007-0450

Tomcat разрешает '\', '% 2F' и '% 5C' [...].

Следующие свойства системы Java были добавлены в Tomcat для дополнительный контроль над обработкой разделителей маршрутов в URL-адресах (оба варианта по умолчанию - false):

  • org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: правда | ложь
  • org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH: правда | ложь

Из-за невозможности гарантировать что все URL-адреса обрабатываются Tomcat как они находятся в прокси-серверах, Tomcat всегда должны быть защищены, как будто нет ограниченный доступ к контексту б.

Влияет: 6.0.0-6.0.9

Итак, если у вас есть URL-адрес с символом% 2F, Tomcat возвращает: "400 Invalid URI: noSlash"

Вы можете включить исправление в Tomcat startup script:

set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%   -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true 

Ответ 6

Вы можете избежать описанных выше предложений двойного кодирования/декодирования и просто использовать HttpServerUtility.UrlTokenEncode и соответствующий UrlTokenDecode.

Ответ 7

Это интересно о .NET 4. В любом случае эта ссылка описывает RFC 1738 и включает в себя, какие символы нуждаются в кодировке и которые просто "небезопасны". текст ссылки

Если мне нужен URL-адрес дружественного SEO (например, если вы хотите разместить тему форума в URL-адресе), пропустите кодировку и замените все, что не A-Z, a-z, 0-9.

public static string CreateSubjectSEO(string str)
    {
        int ci;
        char[] arr = str.ToCharArray();
        for (int i = 0; i < arr.Length; i++)
        {
            ci = Convert.ToInt32(arr[i]);
            if (!((ci > 47 && ci < 58) || (ci > 64 && ci < 91) || (ci > 96 && ci < 123)))
            {
                arr[i] = '-';
            }
        }
        return new string(arr);
    }

Ответ 8

Для входящей закодированной проблемы "/" я смог исправить свою проблему, добавив "*" для перехвата параметра id, а затем смог правильно передать закодированный "/" в элемент управления (параметр представлял собой строку с закодированной '/')

routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{*id}",
            defaults: new 
            { 
                controller = "Control", 
                action = "Action", 
                id = UrlParameter.Optional 
            })

Ответ 9

Как было предложено здесь, когда проблема возникла у разработчиков Symfony 1.x(+ предложено в Комментарии PHP для urlencode()):

  • Кодировать '/' до '% 2F' перед urlencode()
  • Декодировать '% 2F' до '/' после (если необходимо) urldecode()

Примечание: вы можете использовать rawurlencode(), но вам все равно придется дважды указывать '/'.

Преимущества:

  • Избегает необходимости дополнительных процессов экранирования (если заменить "/" специальным символом типа "!" или "_" )
  • Не полагайтесь на любые настройки сервера, такие как AllowEncodedSlashes для Apache

Ответ 10

Просто используйте Server.UrlDecode. Он будет работать, я тестировал.