ASP.NET Нормализация обратных косых черт в прямом разрезе

ASP.NET "нормализует" обратную косую черту в путях запросов для пересылки косых черт, и мне нужно, чтобы они проходили как обратные косые черты (они используются для выполнения поиска в базе данных). Я не против, если сбежать вперед - косые черты пройдут как небезопасные, в отличие от этого вопроса.

config.Routes.MapHttpRoute(
    name: "TransactionsApi",
    routeTemplate: "api/transactions/{*transaction}",
    defaults: new { controller = "transactions", transaction = RouteParameter.Optional }
);

Обратите внимание, что я установил транзакцию для соответствия оставшейся части пути.

Я пробовал следующие URL-адреса (как из браузера, так и из Fiddler):

  • api/transactions/mscorlib.pdb\DFA83312EAB84F67BD225058B188F22B1\mscorlib.pdb
  • api/transactions/mscorlib.pdb\\DFA83312EAB84F67BD225058B188F22B1\\mscorlib.pdb
  • api/transactions/mscorlib.pdb%5CDFA83312EAB84F67BD225058B188F22B1%5Cmscorlib.pdb
  • api/transactions/mscorlib.pdb%5C%5CDFA83312EAB84F67BD225058B188F22B1%5C%5Cmscorlib.pdb

К моменту, когда они попали в мой метод Web API, все они mscorlib.pdb/DFA83312EAB84F67BD225058B188F22B1/mscorlib.pdb. Я проверил текущий HttpContext, и похоже, что ASP.NET выполняет эту нормализацию (а не MVC4).

Возможные решения:

  • При вставке транзакции нормализовать '\' на '/', чтобы независимо от того, какой ASP.NET проходит через поиск, будет успешным. Кажется немного вонючим.
  • Base64 часть {*transaction}, если она содержит обратную косую черту. Не действительно хакерский адрес-бар

Любая идея о том, как заставить ASP.NET не выполнять эту нормализацию?

Ответ 1

Исследование

Я хотел исследовать эту проблему, декомпилируя среду выполнения и следуя коду. Всегда приятно это делать: вы узнаете, как работает среда выполнения, и иногда вы обнаруживаете проблему. Пусть начнется путешествие...

В качестве отправной точки я декомпилирую System.Web с помощью ILSpy, начиная с класса HttpRuntime. Перемещение через public static void ProcessRequest(HttpWorkerRequest wr), ProcessRequestNoDemand, ProcessRequestNow, ProcessRequestInternal...

Здесь я хочу исследовать следующие строки:
httpContext = new HttpContext(wr, false);,
httpContext.Response.InitResponseWriter();,
httpAsyncHandler.BeginProcessRequest(httpContext, this._handlerCompletionCallback, httpContext);.

В HttpContext.HttpContext(HttpWorkerRequest wr, bool initResponseWriter) многое может вызвать следующее:
this.Init(request, response),
new HttpRequest(wr, this).

Точнее HttpContext.GetEurl() (выглядит подозрительно),
Request.InternalRewritePath(VirtualPath.Create(virtualPath), null, true) (безопасный),
VirtualPath.Create(virtualPath) (выглядит очень подозрительно),
virtualPath = UrlPath.FixVirtualPathSlashes(virtualPath); (печально известный!).

Давайте напишем трассировку стека, которая доставит нас сюда:

  • HttpRuntime.ProcessRequest... (несколько методов)
  • new HttpContext(wr, false)
  • this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this));
  • if (!string.IsNullOrEmpty(eurl)) (можем ли мы предотвратить ввод if?)
  • this.Request.InternalRewritePath(VirtualPath.Create(virtualPath), null, true);
  • VirtualPath Create(string virtualPath)
  • unsafe static VirtualPath Create(string virtualPath, VirtualPathOptions options)

Этот последний (небезопасный) метод делает что-то на пути. Сначала есть петля над каждым символом. Если char ниже "." И отличается от "/" и равен "\", то flag = true. После цикла if (flag) (src), тогда может быть выбрано исключение, а virtualPath = UrlPath.FixVirtualPathSlashes(virtualPath); (src).

Теперь кажется, что ничто не поможет нам избежать поездки туда (может быть, дело eurl?).

string FixVirtualPathSlashes(string virtualPath) (src) заменяет обратную косую черту косыми чертами и удаляет дубликаты слэшей. Позор.

Как насчет метода GetEurl? Когда вы читаете src, вы обнаружите, что это вам не поможет.

Заключение

Время выполнения http убивает вашу обратную косую черту без каких-либо задокументированных причин. Вы не можете отключить это поведение.

Обходной путь №1

Теперь должен быть способ. Этот парень, ссылающийся на на этой странице имеет обходное решение. Похоже, что с использованием переписывающего модуля вы можете вернуть исходный URL в конвейер. Мне не очень нравится это решение, потому что я не знаю, что именно происходит. У меня есть другая идея...

Я еще не тестировал эту вещь. Можете ли вы?

Поиск обходного пути # 2 (не найдено)

Что делать, если было место, где был сохранен исходный путь запроса?

Поиск HttpRequest, ни один из Url.OriginalString, RawUrl, Path, ServerVariables не содержит требуемого значения. Даже закрытые поля _filePath, _path, _queryStringText, _rawUrl, _rewrittenUrl, _url.

Поиск в IIS7WorkerRequest, значение уже изменено во время выполнения. Я подозреваю, что IIS делает это, прежде чем нажимать запрос на время выполнения ASP.NET. Похоже, нет никакой надежды.

Ответ 2

Вы пытались применить UrlEncode() к пути перед тем, как сделать запрос?