Безопасное применение путей ввода файлов пользователем в подкаталогах - PullRequest
1 голос
/ 24 августа 2009

Я знаю твердую рекомендацию по безопасности избегать принятия пользовательского ввода, который вы затем используете, чтобы выбрать путь для чтения / записи файла. Однако, если у вас есть базовый каталог, в котором вы хотите хранить данные (например, корень папки ftp), как лучше всего обеспечить, чтобы данные, введенные пользователем, удерживали нас в этой папке?

Например,

Path.Combine (_myRootFolder, _myUserInput)

все еще может вывести нас за пределы _myRootFolder. И это также может быть хитроумным

newPath = Path.Combine (_myRootFolder, _myUserInput) if (newPath.StartsWith (_myRootFolder)) ...

дано что-то вроде "/back/to/myrootfolder/../../and/out/again" от пользователя. Каковы стратегии для этого? Я упускаю ослепительно очевидный метод .NET, который я могу использовать?

Ответы [ 5 ]

6 голосов
/ 24 августа 2009

В приложениях ASP.NET вы можете использовать Server.MapPath(filename), что вызовет исключение, если сгенерированный путь выходит за пределы корня вашего приложения.

Если все, что вам нужно, это безопасное имя файла, и вы просто хотите, чтобы все файлы были там, это станет проще;

    FileInfo file = new FileInfo(
        Server.MapPath(
            Path.Combine(@"c:\example\mydir", filename)));

Если вы находитесь за пределами ASP.NET, как вы указали, вы можете использовать Path.GetFullPath.

string potentialPath = Path.Combine(@"c:\myroot\", fileName);
if (Path.GetFullPath(potentialPath) != potentialPath)
    // Potential path transversal

Или вы вызываете Path.GetFullPath, а затем проверяете, что начало его соответствует каталогу, к которому вы хотите заблокировать.

1 голос
/ 02 марта 2017

Я знаю, что этот поток довольно старый, но чтобы не допустить, чтобы следующие читатели писали код с потенциальными ошибками безопасности, я должен отметить, что использование Path.Combine(arg1, arg2) не сохраняет, когда arg2 напрямую основывается на пользовательский ввод. Когда arg2 является, например, «C: \ Windows \ System32 \ cmd.exe», параметр arg1 будет полностью игнорироваться, и вы предоставите пользователям вашего API или серверного приложения полный доступ ко всей файловой системе.

Поэтому, пожалуйста, будьте очень осторожны при использовании этого метода!

Я придумал это решение, которое должно (afaik) быть безопасным:

    public static string SecurePathCombine(params string[] paths)
    {
        string combinedPath = "";

        foreach (string path in paths)
        {
            string newPath = Path.Combine(combinedPath, path);

            if (!newPath.StartsWith(combinedPath))
                return null;

            combinedPath = newPath;
        }

        if (Path.GetFullPath(combinedPath) != combinedPath)
            return null;

        return combinedPath;
    }
1 голос
/ 24 августа 2009

Я верю, что Path.FullPath сделает то, что вам нужно (хотя я не проверял это):

string newPath = Path.Combine(_myRootFolder, _myUserInput);
string newPath = Path.FullPath(newPath);
if (newPath.StartsWith(_myRootFolder)) ...
0 голосов
/ 24 августа 2009

Что ж, в вашем примере с FTP-сервером вы должны установить домашний каталог пользователей и соответствующие разрешения таким образом, чтобы они не могли перемещаться из папки. По какой причине вы не можете этого сделать?

0 голосов
/ 24 августа 2009

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

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