Envato Elements - pobierasz co chcesz, ile chcesz

Kilka dni temu, w artykule o moim nowym internecie podstawowym (Internet na Kartę w Play) wspomniałem, że po kilku latach, brak stałego i publicznego adresu IP jest dla mnie większym utrudnieniem niż „skacząca prędkość”, czy w ogóle zanikający od czasu do czasu transfer. Dlatego uznałem, że muszę wdrożyć jakieś dodatkowe mechanizmy, które pozwolą mi zniwelować minusy wynikające z dynamicznie przydzielanego adresu IP…

Dynamiczny adres IP przy uwierzytelnieniu dwuskładnikowym na serwerze VPS

Zapewne przeciętny internauta nawet nie zawraca sobie głowy czymś takim jak adres IP, a tym bardziej tym, czy jest on stały (i publiczny), bo najzwyczajniej w świecie nie ma to dla niego znaczenia. Ja jednak mam pod opieką m.in. kilka serwerów (VPS), na których jednym z mechanizmów mających na celu blokowanie nieautoryzowanego dostępu jest uwierzytelnienie dwuskładnikowe, co wymaga podania oprócz nazwy użytkownika i hasła (oraz wskazania odpowiedniego pliku klucza) jednorazowego kodu, generowanego przez programowy token (w moim przypadku Authy zamiast Google Authenticatora).

By jednak sobie trochę ułatwić codzienne obcowanie z serwerami – zwłaszcza podczas korzystania z WinSCP – na niektórych serwerach miałem ustawione tak, że połączenie SSH/SCP z mojego stałego adresu IP nie wymagało każdorazowego podawania kodu jednorazowego. Powiedzmy, że taki kompromis między bezpieczeństwem a wygodą.

Od liku dni korzystam jednak głównie z internetu mobilnego, w którym adres IP jest zmieniany dynamicznie, „co jakiś czas”, a tym samym ręczne ustawienie go w wyjątkach na serwerze byłoby może nie tyle bezcelowe, co… dość mocno absorbujące. Dlatego postanowiłem, że trzeba wdrożyć jakieś rozwiązania, które bez (znacznej) utraty bezpieczeństwa pozwolą mi ponownie wygodnie łączyć się z (wybranymi) serwerami z mojego internetu domowego/biurowego.

Serwer VPN

Pierwszym rozwiązaniem, które uznałem za sensowne w takiej sytuacji, będzie skorzystanie z serwera VPN, który z założenia ma stały adres IP, a więc można ten adres dodać do wyjątków na docelowych serwerach. Do niedawna taką rolę pełnił komputer Raspberry Pi (VPN/PPTP), ale z racji tego, że znajduje się on w mojej sieci, czyli obecnie „za łączem mobilnym”, to nic to nie da.

Można w takiej sytuacji skorzystać z jednej z firm oferujących usługi typu VPN, których obecnie na rynku jest całkiem sporo. Ja jednak postanowiłem, że lepszym rozwiązaniem (i chyba nawet tańszym) będzie postawienie dedykowanego serwera VPS, na którym uruchomię tylko i wyłącznie usługę VPN. Tak na wszelki wypadek.

CloudFlare

Kolejnym rozwiązaniem, które przyszło mi do głowy było skorzystanie z serwisu CloudFlare, gdzie można przygotować jakąś subdomenę, i za pomocą skryptu podstawiać tam aktualny adres IP, który w regularnych odstępach czasu (CRON) będzie odczytywany przez serwery, i podstawiany do odpowiedniego pliku.

Rozwiązanie sensowne, zarazem dość proste do wdrożenia – powiedzmy, że do artykułu poświęconego wykorzystaniu CloudFlare jako serwisu DDNS (DynDNS) trzeba by dopisać rozdział poświęcony odczytywaniu tego adresu z CloudFlare, by podstawić go w odpowiednim pliku konfiguracyjnym. Rozwiązanie ma taką zaletę, że nie potrzeba tu dodatkowego serwera, a więc i nic nie generuje dodatkowych kosztów.

Uznałem jednak, że na potrzeby tego artykułu pójdziemy jeszcze o krok dalej, i zrezygnujemy również z CloudFlare, bo zapewne nie wszyscy korzystają z tej usługi.

Odczytywanie i zapisywanie dynamicznego adresu IP za pomocą skryptów

Postanowiłem, że wykorzystam Raspberry Pi do odczytywania aktualnego adresu IP (tak samo, jak przy CloudFlare jako DDNS) i przekazywania go do zdalnego serwera, na którym kolejny skrypt dokona odpowiedniej modyfikacji plików konfiguracyjnych SSH, tak by dodać mój aktualny adres IP do wyjątków.

Raspberry Pi, czyli sprawdzamy aktualny adres IP

Pierwsze co skrypt musi zrobić, to ustalić aktualny adres IP. Postanowiłem skorzystać z adresu:

https://cdn.pryc.eu/add/myip.php

Możecie zrobić to samo, ale możecie też na jakimś serwerze z obsługą PHP (webserwer) utworzyć plik o nazwie np. myip.php i takiej zawartości:

<?php
echo $_SERVER['REMOTE_ADDR'];
?>

Za pomocą tego pliku (lub podanego wcześniej adresu) będziemy mogli odczytać aktualny adres IP. Oczywiście nie jest to jedyna metoda, ale ja z takiej korzystam od dawna i mi się sprawdza bardzo dobrze.

Kolejnym krokiem jest przygotowanie skryptu, który sprawdzi aktualny adres IP, i w przypadku wykrycia, że się zmienił powiadomi zdalny serwer o tym fakcie:

#!/bin/bash

IP_CONTROL_LAST=1 # 1 - sprawdź czy adres IP uległ zmianie ($IP_LOG_FILE), 0 - zawsze wysyłaj adres IP

# Adres serwera by sprawdzić aktualny IP:
IP_CHECK_URL=https://cdn.pryc.eu/add/myip.php

IP_LOG_FILE=/boot/last-ip.txt # Plik przechowujący ostatni znany adres IP

if [ -z "$IP_CHECK_URL" ]
then
	echo "IP_CHECK_URL is empty!"
	exit 0
else
	IP_NOW=`wget -O - -q $IP_CHECK_URL`
fi

if [ ! -f $IP_LOG_FILE ] && [ "$IP_CONTROL_LAST" = "1" ]
then
    sudo touch $IP_LOG_FILE
fi

if [ $IP_LOG_FILE ] && [ "$IP_CONTROL_LAST" = "1" ]
then
    IP_LAST=$(cat $IP_LOG_FILE)
fi

function f_send_ip() {
	if [ -n "$IP_NOW" ]
	then
		# Polecenie przekazujące do zdalnego serwera adres IP:
		wget -O - -q https://adres.mojego.serwera.vps/newip.php?ip=$IP_NOW > /dev/null
	fi
}

if [ "$IP_CONTROL_LAST" = "1" ]
then
	if [ "$IP_NOW" != "$IP_LAST" ]
	then
		echo $IP_NOW | sudo tee $IP_LOG_FILE > /dev/null
		f_send_ip
	else	
		echo "IP is OK"
	fi
else
	echo $IP_NOW | sudo tee $IP_LOG_FILE > /dev/null
	f_send_ip	
fi

exit 0

Nie jest to skrypt z którego ja korzystam – zostały z niego wyeliminowane wszystkie dodatkowe mechanizmy związane z dodatkowym uwierzytelnieniem. Nie tylko dlatego, by nie zdradzać co i jak wdrożyłem w tym zakresie, ale też po to, by niepotrzebnie nie komplikować/zaciemniać przedstawionego rozwiązania. Ta zasada będzie też dotyczyć wszystkich kolejnych skryptów, które pojawią się w tym artykule.

Serwer (VPS) zdalny

W skrypcie powyżej – w przypadku zmiany adres IP – następuje wywołanie pliku newip.php, który odpowiada za przyjęcie tej informacji (nowy adres IP), oraz zapisanie jej do pliku konfiguracyjnego (na potrzeby artykułu będzie to plik „newip”).

Skrypt PHP (w wersji uproszczonej, o czym już wspominałem) może wyglądać tak:

<?php

if ( !isset( $_GET['ip'] ) ) {
	die();
} else {

	$IP = preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $_GET['ip'] );

	$IP = $_GET['ip'];
	$LogFile = "./newip";

	file_put_contents($LogFile, $IP, LOCK_EX);

	die();

}

?>

W tym momencie do akcji wkracza drugi skrypt, który na podstawie pliku „newip” dokona – jeśli zajdzie taka potrzeba – zmian w konfiguracji usługi SSH na serwerze:

#!/bin/bash

IP_LOG_FILE=/ścieżka/do/pliku/newip

# Odczyt aktualnego IP:
if [ $IP_LOG_FILE ]
then
    IP2SET=$(cat $IP_LOG_FILE)
fi

# Odczyt archiwalnego IP:
CurrentIP=$(sed -n 2p /etc/security/access-local.conf | tail -c +11)

# Porównanie IP:
if [ "$IP2SET" != "$CurrentIP" ]
then
	# Podmiana IP:
	sudo sed -i "2s/"$CurrentIP"/"$IP2SET"/g" /etc/security/access-local.conf  > /dev/null

	# Restart SSH:
	sudo /etc/init.d/ssh restart  > /dev/null

fi

exit

Od razu zwracam uwagę na linijkę:

CurrentIP=$(sed -n 2p /etc/security/access-local.conf | tail -c +11)

Znajduje się tutaj parametr „2p”, który oznacza drugą linijkę w pliku access-local.conf, bo w moim przypadku tam znajduje się zapis, który będziemy odczytywać i w razie potrzeby modyfikować:

+ : ALL : 123.124.125.126

Dotyczy to również linijki:

sudo sed -i "2s/"$CurrentIP"/"$IP2SET"/g" /etc/security/access-local.conf > /dev/null

Tutaj jest to parametr „2s”. Można też lekko zmodyfikować ten zapis, tak, że będzie dokonywał podmiany bezwzględnie, bez szukania konkretnej zawartości do podmiany (starego adresu IP):

sudo sed -i "2s/.*/+ : ALL : "$IP2SET"/g" /etc/security/access-local.conf > /dev/null

Pamiętajcie tylko, by zarówno ten skrypt, jak i ten uruchamiany np. na Raspberry Pi ustawić jako wykonywalny:

sudo chmod 755 /ściażka/do/skryptu/nazwa-skryptu

Niby drobiazg, ale z doświadczenia wiem, że sporo osób o tym zapomina, i potem są problemy, ze skrypt się nie uruchamia…

Podstawowe mechanizmy zabezpieczające

Wywołany komentarzem postanowiłem podać prosty i dość skuteczny sposób, w jaki można dodatkowo zabezpieczyć system przed nieprawioną podmianą adres IP.

Podstawa to HTTPS/SSL, co i tak staje się już standardem. Do tego można dołożyć token, który będzie weryfikowany podczas każdego połączenia ze skryptem PHP, a bez znajomości którego, nie będzie można przekazać nowego adres IP do serwera.

W skrypcie sprawdzającym aktualny adres IP wystarczy lekko zmodyfikować polecenie Wget:

wget -O - -q https://adres.mojego.serwera.vps/newip.php?ip=$IP_NOW&token=WebInsiderPL > /dev/null

Do tego w pliku PHP modyfikujemy pierwszy warunek tak, by sprawdzał czy wywołanie nastąpiło z prawidłowym tokenem:

if ( ( !isset( $_GET['ip'] ) ) && ( !isset( $_GET['token'] ) ) && ( $_GET['token'] != "WebInsiderPL" ) ) { die(); }

Oczywiście zamiast „WebInsiderPL” należy wstawić jakiś unikatowy ciąg znaków. Uważajcie tylko na znaki specjalne (poza a-z, A-Z, 0-9, – i _), bo niektóre z nich (np. „), bez odpowiedniej „otoczki” mogą uszkodzić działanie skryptu.

Można też (dodatkowo) dostęp do pliku PHP zabezpieczyć za pomocą loginu i hasła HTTP…

Odczytywanie adresu IP bezpośrednio z wywołania strony

Można całość zmodyfikować również tak, że klient (Raspberry Pi, telefon, komputer) nie sprawdza jaki ma adres IP, tylko co jakiś czas wywołuje stronę WWW (skrypt PHP), który odczytuje adres IP klienta i dodaje go do wyjątków. W takim wariancie jednak warto wdrożyć token, by przypadkowa osoba nie mogła ustawić adresu IP.

Skrypt PHP w wersji podstawowej, z tokenem może wyglądać tak:

<?php

if ( ( !isset( $_GET['token'] ) ) && ( $_GET['token'] != "WebInsiderPL" ) ) {
	die();
} else {

	$IP = $_SERVER['REMOTE_ADDR'];

	$LogFile = "./newip";
	file_put_contents($LogFile, $IP, LOCK_EX);

	die();
}

?>

W tym momencie, by ustawić adres IP wystarczy na urządzeniu, które będzie się łączyło wywołać adres:

https://adres.mojego.serwera.vps/newip.php?token=WebInsiderPL

Roziwązanie prostrze, może się przydać zwłaszcza tam, gdzie bardziej rozbudowanych skrytpów nie możemy uruchomić (np. na telefonie).

CRON, czyli harmonogram zadań

Na koniec warto jeszcze całość zautomatyzować – bo w końcu po to w ogóle zostały stworzone te skrypty, np. za pomocą systemowego harmonogramu zadań (CRON). Częstotliwość wywoływania skryptów zależy tylko do Was, moim zdaniem 5-10 minut w większości wystarczy:

*/5 * * * * root /ściażka/do/skryptu/nazwa-skryptu >/dev/null 2>&1

Więcej na temat CRONa pisałem w tym artykule, i oczywiście zachęcam, by się z nim zapoznać…

Rozwiązanie, które po prostu działa

Jak już pisałem – przedstawione tutaj rozwiązanie zostało przeze mnie trochę „wykastrowane”, ale tylko o elementy, które nie są niezbędne dla prawidłowego działania, a są związane z dodatkowymi zabezpieczeniami (np. tokeny uwierzytelniające, dzięki którym osoba nieuprawniona nie powinna móc skutecznie wywołać pliku PHP, dodatkowe raporty/powiadomienia).

I choć na początku kierowałem się ku rozwiązaniu z VPNem, to muszę przyznać, że w trakcie kilkudniowych testów tego rozwiązania przekonałem się do niego na tyle, że… w tym czasie z VPNa skorzystałem tylko raz, głównie sprawdzić czy wszystko działa. Co nie znaczy, że nie będę go stopniowo modyfikował, bo jest to jego pierwsza odsłona, i pewnie niektóre elementy można napisać lepiej… ;-)

SSH zamiast PHP

Teoretycznie można zamiast PHP, czyli przekazywania nowego (aktualnego) adresu IP za pomocą wywołania strony internetowej skorzystać z połączenia SSH, i dokonać zdalnej modyfikacji ustawień serwera lub w ten sposób przynajmniej przekazać nowy adres IP.

Ale tu koło się zamyka – bo gdy mamy wymuszone 2FA, to tego typu połączenie (SSH – SSH) nie zadziała. W skrypcie możemy wykorzystać połączenie z loginem i hasłem, a nawet kluczem, ale z 2FA będzie dużo trudniej. Nie dodamy też wcześniej (automatycznie) naszego IP do wyjątków, bo… jest on zmienny, i właśnie po to cała ta zabawa, by go dodać.

(!) Zgłoś błąd na stronie
Potrzebujesz profesjonalnej pomocy? Skontaktuj się z nami!
Spodobał Ci się artykuł? Zapisz się do naszego Newslettera - ZERO SPAMu, same konkrety, oraz dostęp do dodatkowych materiałów przeznaczonych dla subskrybentów!
Na podany adres e-mail otrzymasz od nas wiadomość e-mail, w której znajdziesz link do potwierdzenia subskrypcji naszego Newslettera. Dzięki temu mamy pewność, że nikt nie dodał Twojego adresu przez przypadek. Jeśli wiadomość nie przyjdzie w ciągu najbliższej godziny (zazwyczaj jest to maksymalnie kilka minut) sprawdź folder SPAM.
Roztańczona Karolina skorzystała z promocji dla czytelników WebInsider.pl i zapłaciła 80% mniej za księgowość internetową wFirma
WebInsider poleca księgowość wFirma
WebInsider korzysta z VPSa w HitMe.pl
WebInsider poleca VPSy DigitalOcean
WebInsider poleca serwis Vindicat
Napisz komentarz
wipl_napisz-komentarz_01Jeśli informacje zawarte na tej stronie okazały się pomocne, możesz nam podziękować zostawiając poniżej swój komentarz.

W tej formie możesz również zadać dodatkowe pytania dotyczące wpisu, na które – w miarę możliwości – spróbujemy Ci odpowiedzieć.
Linki partnerskie
Niektóre z linków na tej stronie to tzw. „linki partnerskie”, co oznacza, że jeśli klikniesz na link i dokonasz wymaganej akcji (np. zakup/rejestracja) możemy otrzymać za to prowizję. Pamiętaj, że polecamy tylko te produkty i usługi, z których sami korzystamy, i uważamy, że są tego na prawdę warte… :-)
Znaki towarowe i nazwy marek
W niektórych wpisach (oraz innych miejscach na stronie) mogą być przedstawione/użyte znaki towarowe i/lub nazwy marek, które stanowią własność intelektualną tych podmiotów, a zostały użyte wyłącznie w celach informacyjnych.
Młody Szymon dzięki motywowi Divi od Elegant Themes zrobił stronę dla firmy ojca