2013-04-10 30 views
6

Mam tę procedurę obsługi HTTP, którą utworzyłem, aby zaktualizować informacje w lokalnej bazie danych SQL Express.Łańcuch dezynfekcji, aby zapobiec względnym ścieżkom URI.

Uświadomiłem sobie, że użytkownik może używać względnych ścieżek URI "/../../file.zip" jako ciągu zapytania i będzie mógł pobierać pliki poza obszar zastrzeżony.

Witryna nie jest jeszcze dostępna, więc nie jest to obecnie kwestia bezpieczeństwa, ale naprawdę chciałabym zapobiec takim sytuacjom.

Dodałem prostą linię string.replace, która usuwa wszelkie ".." z zapytania wejściowego.

Czy jest coś jeszcze, co powinienem zrobić, aby to zabezpieczyć?

public void ProcessRequest(HttpContext context) 
{ 
    string filesPath = "C:/Downloads/"; 
    string fileName = context.Request.QueryString["filename"]; 
    fileName = fileName.Replace("'", "''").Replace("..", "").Replace("/", "").Replace("\\", ""); 

    if (!string.IsNullOrEmpty(fileName) && File.Exists(filesPath + fileName)) 
    { 
     context.Response.ContentType = "application/octet-stream"; 
     context.Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", fileName)); 
     context.Response.WriteFile(filesPath + fileName); 
     //Do work to update SQL database here 
    } 
    else 
    { 
     context.Response.ContentType = "text/plain"; 
     context.Response.Write(filesPath + fileName + " Invalid filename"); 
    } 
} 
+1

Generalnie powinieneś odrzucić nieprawidłowe dane wejściowe zamiast próbować usunąć szkodliwe sekwencje - zastanów się, co twój zamiennik robi z './.'. Istnieje również szereg wzorców powodujących dziwaczność, takich jak puste nazwy plików, początkowe i końcowe kropki i spacje, znaki sterujące, 'SHORTN ~ 1.AME' i potencjalnie zarezerwowane nazwy plików (' com1' i inni). Używanie danych wejściowych w nazwach plików jest trudne do uzyskania, [szczególnie w Windows] (http://msdn.microsoft.com/en-gb/library/windows/desktop/aa365247 (v = vs.85) .aspx) - znacznie lepiej jeśli możesz (jak sugeruje Jason) użyć wygenerowanego identyfikatora dla nazwy pliku na dysku lokalnym. – bobince

+0

@bobince Świetne wskazówki tam. Oto dlaczego zadałem to pytanie, ponieważ wiedziałem, że będzie lepszy sposób podejścia do tego problemu, szukałem tylko pewnej wskazówki w tak ważnym temacie. –

Odpowiedz

10

Zwykle używam ten prosty kod, aby sprawdzić ten problem:

(I wpisać go bezpośrednio, więc nie może skompilować, to tylko dać pomysł)

private string getPath(string basePath, string fileName) 
{ 
    var fullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine(basePath, fileName)); 
    if (fullPath.StartsWith(basePath)) 
     return fullPath; 
    return null; 
} 

bramki jest użycie Path.GetFullPath. Ta metoda przetłumaczy dowolne /../ etc na pełną ścieżkę. Następnie sprawdź, czy zwrócona ścieżka znajduje się w dozwolonym katalogu.
Bądź ostrożny, że ta metoda może powróci Slighty inna droga niż oczekiwano, czytać MSDN o szczegółowe wyjaśnienia

+1

Podoba mi się pomysł, który kryje się za tym podejściem - niech system powie Ci, jaki plik ma otworzyć i upewnij się, że jest prawidłowy. Jeśli spróbujesz umieścić na czarnej liście znaki lub ciągi znaków w nazwie pliku, niewątpliwie coś przeoczysz. –

+0

Świetny pomysł również tutaj. To właśnie próbowałem zrobić pierwotnie, ale nie udało mi się znaleźć prawidłowej metody użycia. GetFullPath jest metodą, której nie udało mi się znaleźć. –

2

Mogłeś Request.QueryString["filename"] faktycznie być kluczem, który reprezentuje plik. Klucz może być ciągiem liczbowym lub losowym, jeśli nie chcesz, aby użytkownicy mogli łatwo odgadnąć klucze do plików. Możesz zapisać odwzorowanie w bazie danych i użyć klucza, aby pobrać lokalną nazwę pliku (i być może nazwę pliku, jeśli chcesz, aby te dwie rzeczy różniły się i naprawdę ukryć szczegóły implementacji).

+0

Myślę, że jest to najlepszy sposób, ale zaznaczyłem odpowiedź @Fabske, ponieważ odpowiedziała na moje pierwotne pytanie. Nie jestem pewien, jak to zrobić, ale przyjrzę się użyciu tego podejścia. –