Jak mogę sprawdzić, czy użytkownik jest na hoście lokalnym w PHP?

99

Innymi słowy, jak mogę stwierdzić, czy osoba używająca mojej aplikacji internetowej znajduje się na serwerze, na którym się ona znajduje? Jeśli dobrze pamiętam, PHPMyAdmin robi coś takiego ze względów bezpieczeństwa.

Richie Marquez
źródło

Odpowiedzi:

177

Możesz również użyć $_SERVER['REMOTE_ADDR']adresu IP żądającego klienta, który jest podany przez serwer sieciowy.

$whitelist = array(
    '127.0.0.1',
    '::1'
);

if(!in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
    // not valid
}
Mauris
źródło
2
Dzięki temu łatwiej byłoby to złamać niż sfałszowanie adresu IP. Naprawdę powinieneś to zmienić.
Pekka,
3
@ skcin7 może być ustawieniem twojego serwera. Sprawdź to.
mauris
4
@Pekka 웃 możesz po prostu wysłać np. Host: 127.0.0.1I zostanie on wypełniony HTTP_HOST, więc nie jest to w ogóle metoda niezawodna.
Dejan Marjanović
4
Tak, to zła rada, która w obecnej formie musi zostać zredagowana lub odrzucona.
Pekka
3
Nie zapomnij o IPv6:$whitelist = array('127.0.0.1', '::1');
CrazyMax
26

Jako uzupełnienie, jako funkcja ...

function isLocalhost($whitelist = ['127.0.0.1', '::1']) {
    return in_array($_SERVER['REMOTE_ADDR'], $whitelist);
}
Jens Törnell
źródło
5
Jako dobrą praktykę zalecałbym dodanie „else return false”; tak, że funkcja zawsze zwraca wartość logiczną. Lub alternatywnie, po prostu całkowicie usuń "if", a zamiast tego "return in_array ($ _SERVER ['REMOTE_ADDR'], $ whitelist);"
Joe Irby
15

Nowsi użytkownicy systemu operacyjnego (Win 7, 8) mogą również uznać za konieczne dołączenie zdalnego adresu w formacie IPV6 do swojej białej listy:

$whitelist = array('127.0.0.1', "::1");

if(!in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
    // not valid
}
rgdigital
źródło
14

$_SERVER["REMOTE_ADDR"]powinien podać adres IP użytkownika. Jest to jednak fałszywe.

Sprawdź to pytanie o nagrodę, aby uzyskać bardzo szczegółową dyskusję.

Myślę, że to, co pamiętasz z PHPMyAdmin, jest czymś innym: wiele serwerów MySQL jest skonfigurowanych tak, że ze względów bezpieczeństwa można uzyskać do nich dostęp tylko z lokalnego hosta.

Pekka
źródło
Warto zauważyć, że niektóre serwery MySQL są tak skonfigurowane, że nie są powiązane z interfejsem publicznym. Podobnie, jeśli chciałbyś ograniczyć aplikację PHP w ten sam sposób, powinieneś rozważyć obsługę jej przez instancję apache powiązaną tylko z wewnętrznym interfejsem.
Frank Farmer
8

Przepraszam, ale wszystkie te odpowiedzi wydają mi się straszne. Sugerowałbym przeformułowanie pytania, ponieważ w pewnym sensie wszystkie maszyny są „hostami lokalnymi”.

Pytanie powinno brzmieć; Jak uruchomić różne ścieżki kodu w zależności od tego, na której maszynie jest wykonywany.

Moim zdaniem najłatwiej jest stworzyć plik o nazwie DEVMACHINE lub cokolwiek naprawdę chcesz a potem po prostu sprawdzić

file_exists („DEVMACHINE”)

Pamiętaj, aby wykluczyć ten plik podczas przesyłania do środowiska hostingu na żywo!

To rozwiązanie nie jest zależne od konfiguracji sieci, nie może być sfałszowane i ułatwia przełączanie między uruchomionym „kodem na żywo” i „kodem programisty”.

Daniklad
źródło
6

Wydaje się, że nie powinieneś go używać $_SERVER['HTTP_HOST'], ponieważ jest to wartość w nagłówku http, łatwa do sfałszowania.

Możesz $_SERVER["REMOTE_ADDR"]też użyć , jest to bezpieczniejsza wartość, ale można też podrobić. To remote_addrjest adres, na który Apache zwraca wynik.

nicola
źródło
REMOTE_ADDRmożna sfałszować, jednak jeśli chcesz podrobić to jako 127.0.0.1lub ::1, co wymaga skompromitowania maszyny, w której sfałszowanie REMOTE_ADDRjest najmniejszym z twoich zmartwień. Odpowiednia odpowiedź - stackoverflow.com/a/5092951/3774582
Goose
1

Jeśli chcesz mieć białą listę / allowlist, która obsługuje statyczne adresy IP i dynamiczne nazwy .

Na przykład:

$whitelist = array("localhost", "127.0.0.1", "devel-pc.ds.com", "liveserver.com");
if (!isIPWhitelisted($whitelist)) die();

W ten sposób możesz ustawić listę nazw / adresów IP, które będą mogły (na pewno) zostać wykryte. Nazwy dynamiczne zapewniają większą elastyczność dostępu z różnych punktów.

Masz tutaj dwie typowe opcje, możesz ustawić nazwę w lokalnym pliku hostów lub możesz po prostu użyć jednego dostawcy nazw dynamicznych, który można znaleźć wszędzie.

Ta funkcja CACHES działa, ponieważ gethostbyname jest bardzo powolną funkcją.

Dla tego pupose zaimplementowałem tę funkcję:

function isIPWhitelisted($whitelist = false)
{
    if ( isset($_SESSION) && isset($_SESSION['isipallowed']) )
        { return $_SESSION['isipallowed'];  }

    // This is the whitelist
    $ipchecklist = array("localhost", "127.0.0.1", "::1");
    if ($whitelist) $ipchecklist = $whitelist;

    $iplist = false;
    $isipallowed = false;

    $filename = "resolved-ip-list.txt";
    $filename = substr(md5($filename), 0, 8)."_".$filename; // Just a spoon of security or just remove this line

    if (file_exists($filename))
    {
        // If cache file has less than 1 day old use it
        if (time() - filemtime($filename) <= 60*60*24*1)
            $iplist = explode(";", file_get_contents($filename)); // Read cached resolved ips
    }

    // If file was not loaded or found -> generate ip list
    if (!$iplist)
    {
        $iplist = array(); $c=0;
        foreach ( $ipchecklist as $k => $iptoresolve )
        {
            // gethostbyname: It's a VERY SLOW function. We really need to cache the resolved ip list
            $ip = gethostbyname($iptoresolve);
            if ($ip != "") $iplist[$c] = $ip;
            $c++;
        }

        file_put_contents($filename, implode(";", $iplist));
    }

    if (in_array($_SERVER['REMOTE_ADDR'], $iplist)) // Check if the client ip is allowed
        $isipallowed = true;

    if (isset($_SESSION)) $_SESSION['isipallowed'] = $isipallowed;

    return $isipallowed;
}

Aby zwiększyć niezawodność, możesz zamienić $ _SERVER ['REMOTE_ADDR'] na get_ip_address (), o którym @Pekka wspomniał w swoim poście jako „to pytanie o nagrodę”

Heroselohim
źródło
1
Nie wiem, dlaczego ktoś ustawił negatywną ocenę mojej odpowiedzi, podczas gdy wyraźnie oferuje ona dynamiczne rozpoznawanie nazw, a inni nie. Rozpoznawanie nazw DNS jest powolne, dlatego wymagane są rozdzielczości pamięci podręcznej.
Heroselohim
1

Co powiesz na porównanie w $_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR']celu ustalenia, czy klient znajduje się na tym samym komputerze co serwer?

Eugen Wesseloh
źródło
$_SERVER['SERVER_ADDR']nie zawsze niezawodnie zwraca adres serwera, np. jeśli używasz load balancerów, zwraca adres IP load balancera.
Mike W
-2

Znalazłem łatwą odpowiedź.

Ponieważ wszystkie dyski lokalne mają C: lub D: lub F: ... itd.

Po prostu wykryj, czy druga postać to:

if ( substr_compare(getcwd(),":",1,1) == 0)
{
echo '<script type="text/javascript">alert(" The working dir is at the local computer ")</script>';
    $client_or_server = 'client';
}
else
{
echo '<script type="text/javascript">alert(" The working dir is at the server ")</script>';
    $client_or_server = 'server';
}
Scoobeedo Cool
źródło