Artykuł ten będzie opisywał podstawowe techniki zabezpieczenia swojego kodu php
przed niepotrzebnymi dziurami które mogą wykorzystać nieodpowiednie osoby.
Część pierwsza będzie dotyczyć głównie zabezpieczeń podczas używania include().
Druga zaś podczas używania bazy danych (mysql).
No to zaczynajmy.
1. ======== Include ==========
Przyjmijmy, że nasz skrypt który będziemy zabezpieczać ma taką postać.
Kod:
<?php
echo"To jest zawartość strony includowanej";
include($_GET['strona']);
echo"Koniec";
?>
Jak widać adres strony do zincludowania jest pobierany ze zmiennej $strona
przysyłanej metodą GET ( $_GET['strona'] ) czyli po prostu z paska adresu
naszej przeglądarki. Jak wiemy z wcześniejszych moim artykułów wystarczy
w zmiennej $strona podać adres do odpowiednio spreparowanego przez nas
pliku PHP abyśmy mogli zrobić bardzo dużo.
Teraz pomyślmy jak to zabezpieczyć. Jednym ze sposobów jest wykorzystanie
funkcji file_exist() która to sprawdza czy plik ( w tym przypadku podany w zmiennej $strona )
znajduje się na LOKALNYM serwerze. Podaje ona fałsz w przypadku stosowania do plików
znajdujących się na innych serwerach. Nasz kod może mieć taką postać.
Kod:
<?php
echo"To jest zawartość strony includowanej";
if (file_exist($_GET['strona'])) {
include($_GET['strona']);
} else {
echo "Plik nie znajduje się na serwerze";
}
echo"Koniec";
?>
Jest to dobry sposób ale ma pewną wadę. Nadal ktoś ma możliwość zincludowania
dowolnego pliku jednakże już tylko znajdującego się i nas na koncie.
Kolejnym dobrym zabezpieczeniem jest wykorzystanie tego, iż pliki includowane będą mogły
pochodzić tylko z danego katalogu. Oto kod:
Kod:
<?php
echo"To jest zawartość strony includowanej";
include("includy/" . $_GET['strona']);
echo"Koniec";
?>
Teraz wchodząc np. na stronę index.php zawierającą podany wyżej kod
(adres ma postać
http://serwer.com/index.php?strona=test.php ) zostanie zincludowwany plik test.php
z katalogu "includy".
Kolejnym zabezpieczeniem, może być np. możliwość includowania plików tylko o podanym przez nas
rozszerzeniu.
Połączymy ten kod z tym wcześniejszym.
Kod:
<?php
echo"To jest zawartość strony includowanej";
include("includy/" . $_GET['strona'] . ".inc");
echo"Koniec";
?>
Teraz po wejściu na
http://serwer.com/index.php?strona=test zostanie zincludowany plik test.inc z
katalogu "includy". Może wytłumaczę czemu tak na wszelki wypadek. Otóż adres przekazany do funkcji
ma postać " includy/" . $_GET['strona'] . ".inc " A więc przypisując zmiennej $strona
wartość "test" otrzymujemy includy/test.inc. Kapujecie ?? Mam nadzieję :)
Wszystkie powyższe sposoby mają nadal jedną lukę. Ktoś może wpisać taki oto adres:
(pierwszy skrypt)
http://serwer.com/index.php?strona=../../plik.php
lub (dla drugiego skryptu)
http://serwer.com/index.php?strona=../../plik
Wtedy to zaincludowany zostanie plik znajdujący się o dwa katalogi powyżej obecnego.
Aby i temu zaradzić należy wykorzystać funkcję basename()
Kod:
<?php
echo"To jest zawartość strony includowanej";
include("includy/" . basename($_GET['strona']) . ".inc");
echo"Koniec";
?>
Taki zapis jest bardzo bezpieczny.
Teraz wg mnie najlepszy sposób na zabezpieczenie się. Wykorzystamy instrukcję switch.
Ma ona taką postać:
Kod:
switch($zmienna) {
case 1:
echo "coś tam"
break;
case 2:
echo "coś innego";
break;
}
Polega ona na tym, że dla danej wartości zmiennej $zmienna ( w tym przypadku '1' lub '2' )
przechodzi do odpowiedniego bloku instrukcji. Nasz kod może mieć np. taką postać.
Kod:
<?php
echo"To jest zawartość strony includowanej";
switch ($_GET['strona'])
{
case 'test1':
include("test1.php");
break;
case 'test2':
include("test2.inc");
break;
case 'stronka':
include("strona.htm");
break;
}
echo"Koniec";
?>
Ważną rzeczą jest pamiętanie, aby na końcu każdego bloku "case" umieszczać instrukcję "break;"
która powoduje przerwanie wykonywania dalszej części instrukcji "switch".
Jest to wg mnie najlepszy sposób i ja właśnie taki zawsze stosuję.
2. ======== MySQL ==========
Naszym kolejnym etapem edykacji będzie baza mysql.
Jednym z głównych zabezpieczeń jest taka konfiguracja, aby dany użytkownik, z którego konta
będziemy wykonywać zapytania sql miał udostępnione tylko koniecznie potrzebne mu
instrukcje sql i miał dostęp tylko do baz do których dostęp jest mu konieczny.
Wtedy to w razie jakiegoś naruszenia bezpieczeństwa, straty powinny być o wiele mniejsze.
Kolejnym zabezpieczeniem ( bardzo ważnym) jest filtrowanie wszystkich zmiennych przy pomocy
których przekazujemy coś do zapytań sql. Przykładem może być np. takie zapytanie:
$sql = "SELECT * FROM tabela WHERE kolumna_id = '$id'";
W Internecie jest dużo informacji czemu taki zapis jest niebezpieczny i jak go wykorzystać.
Aby zabezpieczyć się przed niezamierzonymi danymi przekazanymi do tej instrukcji sql wykorzystamy
filtrowanie zmiennej. Pomoże nam w tym funkcja addslashes() która to wstawia przed znaki specjalne
jak choćby " i ' znak \ który powoduje ich ignorowanie przez mysql i traktowanie jako zwykły tekst.
Teraz mały skrypt
Kod:
<?php
mysql_pconnect("localhost", "user", "password");
mysql_select_db("baza_testowa");
$id = addslashes($_GET['id']);
$sql = "SELECT * FROM tabela WHERE kolumna_id = '$id'";
$result = mysql_query($sql);
(... i tak dalej to nie art o nauce mysql ... )
?>
Ok. Teraz przypuśćmy, że do bazy danych zapisaliśmy jakieś dane wcześniej filtrując je przy pomocy
addslashes() i teraz chcemy je pobrać. Co się okazuje ?? Jeśli używaliśmy w tym zapisywanym
tekście np. znaków ' bądź " po ich odczytanie uzyskamy w ich miejscu odpowiedni \' i \" .
Jednak jest prosta funkcja która przekształci z powrotem przefiltrowany tekst przy pomocy addslashes()
a jest nią ... stripslashes().
Teraz mały przykład:
Kod:
<?php
mysql_pconnect("localhost", "user", "password");
mysql_select_db("baza_testowa");
$sql = "SELECT pole_autor FROM tabela WHERE kolumna_id = '1'";
$result = mysql_query($sql);
$autor = mysql_result($result, 0, pole_autor);
$autor = stripslashes($autor);
(... i tak dalej to nie art o nauce mysql ... )
?>
I mamy już normalny tekst.
------------------------------------------------------
autor: Vengeance - vengeance(at)gazeta(dot)pl
Artykułu NIE wolno publikować bez zgody autora!