2009-04-29 4 views
2

У меня есть rootPath, которому я доверяю, и relativePath, которого я не знаю. Я хочу объединить их таким образом, чтобы я мог быть уверен, что результат находится под rootPath и что пользователь не может использовать .., чтобы вернуться к исходной точке. Я делать хочу относительный путь, чтобы такие вещи, как: hello\..\world == worldБезопасная версия Path.Combine

ответ

5

System.IO.Path.GetFullPath?

Чтобы развернуть: используйте Path.Combine, затем вызовите GetFullPath на результат и убедитесь, что этот результат начинается с rootPath.

Он не защитит вас от жестких ссылок, но он должен поймать простые вещи, такие как двойные точки.

выше, как код:

string Resolve(string fileName) 
{ 
    string root = FileRoot(); 
    string ret = Path.GetFullPath(Path.Combine(root, fileName)); 
    if (ret.StartsWith(root.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar)) return ret; 
    throw new ArgumentException("path resolved to out of accesable directroy"); 
} 
+0

мне нравится: D – BCS

+3

Однако, если корень не заканчивается с \, это все еще можно играть в ограниченный трюк - в конечном итоге, в другом каталоге, в другом корневом, который начинается с этого в качестве префикса. Например, root может быть \ zip \ zop, относительный путь .. \ zopper \ zup, вы попадаете в \ zip \ zopper \ zup, за пределами дерева, внедренного в \ zip \ zop, но все еще удовлетворяющего тесту StartsWith. Небольшой риск, но не ноль. –

+1

Хороший угловой футляр ... собирается добавить это к коду. –

-1

Одна вещь, которую вы можете сделать, это посчитать количество слэш (\) и двойных точек (..), и убедитесь, что число двойных точек меньше числа обратных косых черт. Чтобы переместиться выше rootPath в структуру папок, вам понадобится по крайней мере столько обратных косых черт, что и двойные точки - таким образом, если вы разрешите только relativePath с по меньшей мере еще одной обратной косой чертой, вы должны быть в безопасности.

+0

но \ .. \ .. \ это \ уходит \ кто \ knowns \ где – BCS

+0

я думаю, вы в конечном итоге нужно сохранить текущий счет – BCS

2

Вы можете просто позвонить Path.GetFullPath() и проверить, если он начинается с вашим доверенным rootPath. Если вы склонны к паранойи, проверьте также, что у rootPath.

public Boolean IsPathSafe(String rootPath, String relativePath) 
{ 
    return rootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) && 
    Path.IsPathRooted(rootPath) && 
    Patch.Combine(rootPath, relativePath).GetFullPath().StartsWith(rootPath); 
} 

Для объяснения первого теста см. Комментарий Алексея Мартелли относительно ответа технофила.