versão segura de Path.Combine
-
03-07-2019 - |
Pergunta
Eu tenho um rootPath
que eu confio e uma relativePath
que eu não. Eu quero combiná-los de tal maneira que eu posso ter certeza de que o resultado está sob rootPath
e que o usuário não pode usar ..
para voltar passado o ponto de partida. I não quer o caminho relativo para permitir que coisas como: hello\..\world
== world
Solução
Para expandir:. Uso Path.Combine, em seguida, chamar GetFullPath no resultado e verificar se esse resultado começa com rootPath
Ele não vai protegê-lo contra hardlinks, mas deve pegar coisas simples como duplas pontos.
acima como código:
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");
}
Outras dicas
Você poderia simplesmente chamar Path.GetFullPath()
e verificar se ele começa com a sua rootPath
confiável. Se você tende a paranóia, verificar também que rootPath
está enraizada.
public Boolean IsPathSafe(String rootPath, String relativePath)
{
return rootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
Path.IsPathRooted(rootPath) &&
Patch.Combine(rootPath, relativePath).GetFullPath().StartsWith(rootPath);
}
Para uma explicação do primeiro teste ver o comentário de Alex Martelli sobre a resposta de technophile.
Uma coisa que você pode fazer é contar o número de barras invertidas (\
) e double-pontos (..
), e certifique-se que o número de duplas-pontos é menor do que o número de barras invertidas. A fim de ir acima da rootPath
em sua estrutura de pastas, você precisará de pelo menos tantas barras invertidas como pontos duplos -. Assim, se você só permitem relativePath
s com pelo menos mais uma barra invertida, você deve ser seguro