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
$result = "SELECT fields FROM table WHERE id = '".mysql_real_escape_string($_POST['id'])."'";
2. W drugim przypadku (atrybut zawierający adres URL) nie ma sensuhtmlspecialchars
w ogóle; w takich przypadkach należy zakodować dane wejściowe przy użyciu schematu kodowania adresu URL, nprawurlencode
. za pomocą . W ten sposób użytkownik nie może wstawićjavascript:
et al.Take a whitelist approach and only let through the chars which are good.
lista zawsze coś pominie. +1Oprócz doskonałej odpowiedzi Cheekysoft:
Naprawdę nie ma srebrnej kuli do zapobiegania wstrzykiwaniu HTML (np. Cross-site scripting), ale możesz to osiągnąć łatwiej, jeśli używasz biblioteki lub systemu szablonów do tworzenia HTML. Przeczytaj dokumentację, aby dowiedzieć się, jak odpowiednio uciec od rzeczy.
W HTML rzeczy muszą być chronione inaczej w zależności od kontekstu. Jest to szczególnie prawdziwe w przypadku ciągów umieszczanych w JavaScript.
źródło
Zdecydowanie zgodziłbym się z powyższymi postami, ale mam jedną małą rzecz do dodania w odpowiedzi na odpowiedź Cheekysoftu, a konkretnie:
Zakodowałem małą, szybką funkcję, którą umieściłem w mojej klasie bazy danych, która usunie wszystko, co nie jest liczbą. Używa preg_replace, więc prawdopodobnie jest nieco bardziej zoptymalizowana funkcja, ale działa w mgnieniu oka ...
Więc zamiast używać
użyłbym
i bezpiecznie uruchomi zapytanie
Jasne, to właśnie powstrzymało wyświetlanie poprawnego wiersza, ale nie sądzę, żeby to był duży problem dla każdego, kto próbuje wstrzyknąć sql do Twojej witryny;)
źródło
return preg_match('/^[0-9]+$/',$input) ? $input : 0;
Ważnym elementem tej układanki są konteksty. Ktoś wysyłający jako identyfikator „1 OR 1 = 1” nie stanowi problemu, jeśli zacytujesz każdy argument w zapytaniu:
Co skutkuje w:
co jest nieskuteczne. Ponieważ unikasz ciągu, dane wejściowe nie mogą wyrwać się z kontekstu ciągu. Przetestowałem to do wersji 5.0.45 MySQL i użycie kontekstu łańcuchowego dla kolumny z liczbami całkowitymi nie powoduje żadnych problemów.
źródło
Działa dobrze, nawet lepiej w systemach 64-bitowych. Uważaj jednak na ograniczenia systemu w adresowaniu dużych liczb, ale w przypadku identyfikatorów baz danych działa to świetnie w 99% przypadków.
Powinieneś także używać jednej funkcji / metody do czyszczenia wartości. Nawet jeśli ta funkcja jest tylko opakowaniem dla mysql_real_escape_string (). Czemu? Ponieważ pewnego dnia, gdy zostanie znaleziony exploit do preferowanej metody czyszczenia danych, wystarczy zaktualizować go tylko w jednym miejscu, a nie wyszukiwać i zamieniać w całym systemie.
źródło
dlaczego, och, DLACZEGO, nie umieszczasz cudzysłowów wokół danych wejściowych użytkownika w instrukcji sql? wydaje się całkiem głupie, żeby tego nie robić! dodanie cudzysłowów do instrukcji sql uczyniłoby "1 lub 1 = 1" bezowocną próbą, nie?
więc teraz powiesz: „a co, jeśli użytkownik umieści cudzysłów (lub podwójne cudzysłowy) w danych wejściowych?”
cóż, łatwe rozwiązanie: po prostu usuń cudzysłowy wprowadzone przez użytkownika. np
input =~ s/'//g;
. : . teraz wydaje mi się, że dane wejściowe użytkownika byłyby zabezpieczone ...źródło