Jeśli chodzi o zapytania do bazy danych, zawsze staraj się używać przygotowanych zapytań parametrycznych. mysqli
I PDO
biblioteki obsługują. Jest to nieskończenie bezpieczniejsze niż używanie funkcji ucieczki, takich jak mysql_real_escape_string
.
Tak, w mysql_real_escape_string
rzeczywistości jest to po prostu funkcja ucieczki ciągu. To nie jest magiczna kula. Wszystko, co zrobi, to unikanie niebezpiecznych znaków, aby można było ich bezpiecznie używać w pojedynczym ciągu zapytania. Jeśli jednak nie wyczyścisz wcześniej swoich danych wejściowych, będziesz podatny na niektóre wektory ataku.
Wyobraź sobie następujący SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Powinieneś być w stanie zobaczyć, że jest to podatne na wykorzystanie.
Wyobraź sobie, że id
parametr zawiera wspólny wektor ataku:
1 OR 1=1
Nie ma tam żadnych ryzykownych znaków do zakodowania, więc przejdą one prosto przez uciekający filtr. Opuszczając nas:
SELECT fields FROM table WHERE id= 1 OR 1=1
Co jest pięknym wektorem iniekcji SQL i pozwoliłoby atakującemu zwrócić wszystkie wiersze. Lub
1 or is_admin=1 order by id limit 1
który produkuje
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Dzięki temu osoba atakująca może zwrócić dane pierwszego administratora w tym całkowicie fikcyjnym przykładzie.
Chociaż te funkcje są przydatne, należy ich używać ostrożnie. Musisz upewnić się, że wszystkie dane wejściowe z sieci są do pewnego stopnia zweryfikowane. W tym przypadku widzimy, że możemy zostać wykorzystani, ponieważ nie sprawdziliśmy, czy zmienna, której używaliśmy jako liczba, była w rzeczywistości numeryczna. W PHP powinieneś szeroko używać zestawu funkcji, aby sprawdzić, czy dane wejściowe są liczbami całkowitymi, zmiennoprzecinkowymi, alfanumerycznymi itp. Ale jeśli chodzi o SQL, zwracaj szczególną uwagę na wartość przygotowanej instrukcji. Powyższy kod byłby bezpieczny, gdyby był przygotowaną instrukcją, ponieważ funkcje bazy danych wiedziałyby, że 1 OR 1=1
nie jest to poprawny literał.
Co do htmlspecialchars()
. To samo w sobie pole minowe.
W PHP jest prawdziwy problem polegający na tym, że ma cały wybór różnych funkcji ucieczki związanych z HTML-em i nie ma jasnych wskazówek, które dokładnie funkcje robią.
Po pierwsze, jeśli jesteś wewnątrz tagu HTML, masz poważne kłopoty. Patrzeć na
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Jesteśmy już w tagu HTML, więc nie musimy <lub> robić nic niebezpiecznego. Nasz wektor ataku mógłby być po prostujavascript:alert(document.cookie)
Teraz wynikowy HTML wygląda tak
<img src= "javascript:alert(document.cookie)" />
Atak przebiega prosto.
Pogarsza się. Czemu? ponieważ htmlspecialchars
(nazywane w ten sposób) koduje tylko podwójne cudzysłowy, a nie pojedyncze. Więc gdybyśmy mieli
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Nasz zły napastnik może teraz wprowadzić zupełnie nowe parametry
pic.png' onclick='location.href=xxx' onmouseover='...
daje nam
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
W takich przypadkach nie ma magicznej kuli, wystarczy, że sam wymyślisz dane wejściowe. Jeśli spróbujesz odfiltrować złe postacie, z pewnością poniesiesz porażkę. Podejdź do białej listy i przepuszczaj tylko te znaki, które są dobre. Spójrz na ściągawkę XSS, aby zobaczyć przykłady tego, jak różnorodne mogą być wektory
Nawet jeśli używasz htmlspecialchars($string)
poza tagami HTML, nadal jesteś podatny na ataki z użyciem wielobajtowych zestawów znaków.
Najskuteczniejsze jest użycie kombinacji mb_convert_encoding i htmlentities w następujący sposób.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Nawet to sprawia, że IE6 jest podatny na ataki ze względu na sposób, w jaki obsługuje UTF. Możesz jednak powrócić do bardziej ograniczonego kodowania, takiego jak ISO-8859-1, dopóki nie spadnie użycie IE6.
Aby uzyskać bardziej szczegółowe badanie problemów wielobajtowych, zobacz https://stackoverflow.com/a/12118602/1820