2010-08-22 11 views
6

Mój przyjaciel znalazł problem w moim skrypcie, daje dostęp do plików root.PHP secure root

Ten url daje plik passwd:

http://site.com/attachment.php?file=../../../../../../etc/passwd 

jak uciec tę lukę?

+3

* (odniesienia) * http: //en.wikipedia. org/wiki/Directory_traversal – Gordon

+0

Jak zaznaczył @Starx, staraj się unikać używania ścieżek plików jako identyfikatorów dokumentów (istnieją inne problemy, poza przeglądaniem katalogów). (Pomysł @MartIXa na temat (md5) hashing może pomóc w realizacji lean). Ponadto dobrym pomysłem jest, aby ** nie uruchamiać serwera jako root **. Użyj oddzielnego użytkownika, który ma tylko prawa w systemie, które są niezbędne do wykonania jego zadania. – zpea

+0

(To znaczy, że masz dostęp do plików tylko do odczytu przez użytkownika root, takich jak '/ etc/shadow'.'/Etc/passwd' jest czytelny dla każdego użytkownika w nowoczesnych Unixach, oczywiście) – zpea

Odpowiedz

4

Istnieje kilka różnych rozwiązań. Jeśli może istnieć tylko nazwa pliku, rozwiązanie basename() będzie działać.

Jednakże, jeśli to może być ścieżka bardziej złożone rozwiązanie jest potrzebne

//assume current directory, but can be set anything. Absolute path of course 
$basedir = dirname(__FILE__); 
//assume our files are below document root. 
//Otherwise use it's root dir instead of DOCUMENT_ROOT 
$filename = realpath($_SERVER['DOCUMENT_ROOT'].$_GET['file']); 
if (substr($filename,0,strlen($basedir)) !== $basedir) { 
    header ("HTTP/1.0 403 Forbidden"); 
    exit; 
} 

jest również rozwiązaniem użytecznym konfiguracja PHP open_basedir

14

Nie pobieraj plików za pomocą ciągu URL ... Określ unikalne identyfikatory, aby wskazać plik, a nie ścieżki.

Być może widzieliście pliki do pobrania takie jak te http://www.mysite.com/download.php?id=23423, co robią, użyj tego identyfikatora, aby pobrać nazwę pliku i ścieżkę z bazy danych, a następnie pobrać ją.

1

Przypuszczam, że masz katalog, w którym przechowywane są wszystkie załączniki.

Sprawdź tylko, czy plik znajduje się w twoim katalogu.

// http://www.php.net/manual/en/function.basename.php 
// http://cz.php.net/manual/en/function.file-exists.php 
if (file_exists($attachments_path . "/" . basename($_GET['file'])) { 
    // do work 
} 

Starx opublikował rozwiązanie, które wydaje się w porządku. Można to zrobić bez bazy danych. Jeśli ktoś załaduje plik, możesz zapisać plik jako md5($filename).$extension i użyć swojego skryptu.

+1

Więc jeśli W katalogu załączników znajduje się plik o nazwie "passwd", kod umożliwia także pobranie pliku/etc/passwd? Nie jestem programistą PHP, ale myślę, że powinieneś bardziej otwarcie powiedzieć, że plik, do którego należy uzyskać dostęp, powinien być utworzony w taki sam sposób: $ filename = $ attachments_path. "/". basename ($ _ GET ['plik']) –

3

Możesz użyć realpath() i dirname(), aby sprawdzić adresy URL przed $_SERVER['DOCUMENT_ROOT'] (lub innego katalogu, który jest "bezpieczny" do pobrania).

Jeśli wynik realpath() wskazuje poza bezpiecznym katalogiem, można odrzucić żądanie pobrania.

Istnieje również dyrektywa bezpieczeństwa open_basedir (i opcja środowiska wykonawczego od wersji 5.3).