Проверьте, чтобы строка пути не поднималась в родительскую папку. - PullRequest
0 голосов
/ 05 ноября 2018

Моя бизнес-логика принимает строку пути к папке для чтения папки / файла. Однако, как того требует безопасность, пользователь может получить доступ только к этой папке. Например:

Их папка: C: \ foo \ user \ bar, они могут получить доступ к C:\foo\user\bar\data\.a.b..txt по https://www.example.com/download?path=data/.a.b..txt

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

        var result = this.ResultFolder; // The user folder (\user\bar as in the example)

        if (!string.IsNullOrEmpty(path))
        {
            path = path.Replace("/", @"\");

            if (path.StartsWith(@"\"))
            {
                path = path.Substring(1);
            }

            if (path.StartsWith('\\') || path.Contains("..\\"))
            {
                throw new InvalidDataException("Forbidden Path.");
            }

            result = Path.Combine(result, path);
        }

В основном, что я делаю:

  • Заменить все / на \, поэтому мне нужно беспокоиться только об одном символе разделения.

  • Запрос позволяет начать путь с \, он считается ничем.

  • Теперь, если пользователь пытается быть злонамеренным (используя \\ для перехода в корневой каталог), или пытается подняться на уровень с помощью ..\ (обратите внимание, прежде чем я использовал только .., но получите ложный случай, потому что это допустимое имя файла / папки)

Это правильно и безопасно еще? Есть ли какой-нибудь каркасный метод, который помогает с этим?

1 Ответ

0 голосов
/ 05 ноября 2018

Вот решение, которое использует Path.GetFullPath(string path):

Создать эту функцию:

private static bool VerifyPathUnderRoot(string pathToVerify, string rootPath = ".")
{
    var fullRoot = Path.GetFullPath(rootPath);
    var fullPathToVerify = Path.GetFullPath(pathToVerify);
    return fullPathToVerify.StartsWith(fullRoot);
}

Затем вы можете проверить это с помощью кода, подобного следующему:

 var paths = new[]
 {
     "somepath/somefile.xxx",
     "..\\somepath/somefile.xxx",
     @"C:\this\that\the.other",
 };
 foreach (var path in paths)
 {
     var isOk = VerifyPathUnderRoot(path);
     var okString = isOk ? "OK" : "No";
     Debug.WriteLine($"{okString}: {path}");
 }

, что приводит к этому в области вывода отладчика:

OK: somepath/somefile.xxx
No: ..\somepath/somefile.xx
No: C:\this\that\the.other

Я дважды использую GetFullPath, чтобы канонизировать пути (следя за тем, чтобы все косые черты заканчивались одинаково и т. Д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...