Czy muszę chronić się przed SQL injection, jeśli użyłem rozwijanego menu?

Rozumiem, że nigdy nie należy ufać wejściom użytkownika z formularza, głównie ze względu na szansę na SQL injection.

Jednakże, czy dotyczy to również formularza, w którym jedyne dane wejściowe pochodzą z listy rozwijanej(patrz poniżej)?

Zapisuję $_POST['size'] do sesji, która jest następnie używana w całej witrynie do odpytywania różnych baz danych (za pomocą mysqli Select query) i każde wstrzyknięcie SQL z pewnością zaszkodzi (ewentualnie upuści) je.

Nie ma obszaru dla wpisanego użytkownika do zapytania bazy danych, tylko rozwijane.

<form action="welcome.php" method="post">
<select name="size">
  <option value="All">Select Size</option> 
  <option value="Large">Large</option>
  <option value="Medium">Medium</option>
  <option value="Small">Small</option>
</select>
<input type="submit">
</form>
Author: doppelgreener, 2014-03-20

11 answers

Możesz zrobić coś tak prostego, jak Poniższy przykład, aby upewnić się, że opublikowany rozmiar jest tym, czego oczekujesz.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

Następnie użyj mysqli_*, jeśli używasz wersji php > = 5.3.0, którą powinieneś być, aby zapisać wynik. Jeśli jest używany poprawnie, pomoże to w SQL injection.

 68
Author: Oliver Bayes-Shelton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 13:27:53

Tak, musisz się przed tym chronić.

Pozwól, że pokażę Ci dlaczego, używając konsoli programisty Firefoksa:

edytowałem jedną z wartości z listy rozwijanej, aby była instrukcją drop table

Jeśli nie oczyścisz tych danych, twoja baza danych zostanie zniszczona. (Może to nie jest całkowicie poprawne polecenie SQL, ale mam nadzieję, że udało mi się osiągnąć swój punkt.)

To, że ograniczyłeś opcje dostępne w rozwijanym menu , nie oznacza, że ograniczyłeś dane, które mogę wysłać twojemu serwerowi.

If you tried to ogranicz to dalsze korzystanie z zachowania na swojej stronie, moje opcje obejmują wyłączenie tego zachowania lub po prostu napisanie niestandardowego żądania HTTP na serwerze, które imituje przesłanie formularza. Jest narzędzie o nazwie curl do tego właśnie służy, a ja myślę, że komenda do wysłania tego SQL injection i tak wyglądałaby mniej więcej tak:

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(może to nie jest całkowicie poprawne polecenie curl, ale znowu, mam nadzieję, że zrozumiałem swój punkt widzenia w poprzek.)

Więc powtórzę:

Nigdy nie ufaj wejściom użytkownika. Zawsze się Chroń.

Nie zakładaj, że jakiekolwiek wejście użytkownika jest kiedykolwiek bezpieczne. Jest to potencjalnie niebezpieczne, nawet jeśli dotrze za pomocą innych środków niż formularz. Nic z tego nie jest wystarczająco wiarygodne, aby zrezygnować z ochrony przed SQL injection.

 192
Author: doppelgreener,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 09:03:45

Ponieważ to pytanie zostało oznaczone SQL-injection , oto odpowiedź dotycząca tego konkretnego rodzaju ataku:

Jak już powiedziano w komentarzach, musisz użyć gotowych instrukcji dla każdego pojedynczego zapytania z dowolnymi zmiennymi danymi, z bez wyjątków .

Niezależnie od jakichkolwiek rzeczy HTML!
Ważne jest, aby zrozumieć, że zapytania SQL muszą być odpowiednio sformatowane niezależnie od zewnętrznych czynników, czy to HTML wejście lub cokolwiek innego.

Chociaż możesz użyć białej listy sugerowanej w innych odpowiedziach w celu walidacji danych wejściowych, nie powinno to wpływać na żadne działania związane z SQL - muszą pozostać takie same, bez względu na to, czy zatwierdziłeś wejście HTML, czy nie. Oznacza to, że przy dodawaniu zmiennych do zapytania nadal trzeba używać instrukcji prepared.

Tutaj znajdziesz dokładne wyjaśnienie, dlaczego przygotowane oświadczenia są koniecznością i jak je właściwie wykorzystać, a gdzie nie zastosowanie i co zrobić w takim przypadku: The Hitchhiker ' s Guide to SQL Injection protection

Również to pytanie zostało oznaczone tagiem mysqli . Domyślam się, że głównie przez przypadek, ale w każdym razie muszę cię ostrzec, że raw mysqli nie jest odpowiednim substytutem dla starych funkcji mysq_ * . Po prostu dlatego, że jeśli jest używany w starym stylu, nie doda żadnych zabezpieczeń.Choć poparcie dla przygotowanych wypowiedzi jest bolesne i kłopotliwe, do tego stopnia, że przeciętny użytkownik PHP nie jest w stanie ich w ogóle wykorzystać. Tak więc, jeśli nie ma opcji ORM lub jakiejś biblioteki abstrakcji, to PDO jest twoim jedynym wyborem.

 44
Author: Your Common Sense,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:33

Tak.

Każdy może sfałszować cokolwiek dla wartości, które faktycznie są wysyłane --

Więc, do sprawdzania rozwijanych menu, możesz po prostu sprawdzić, czy wartość, z którą pracujesz, była w rozwijanym menu - coś takiego byłoby najlepszym (najbardziej rozsądnym paranoikiem) sposobem:

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}
 12
Author: rm-vanda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-22 03:09:57

Jednym ze sposobów ochrony przed użytkownikami zmieniającymi listę rozwijaną za pomocą konsoli jest używanie w nich tylko wartości całkowitych. Następnie możesz sprawdzić, czy wartość POST zawiera liczbę całkowitą i użyć tablicy, aby przekonwertować ją na tekst w razie potrzeby. Np.:

<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '<select name="size">';
foreach($sizes as $i => $s) {
    echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';

Następnie możesz użyć $size w zapytaniu ze świadomością, że będzie ono zawierać tylko FALSE lub liczbę całkowitą.

 8
Author: Styphon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 14:01:12

Pozostałe odpowiedzi obejmują już to, co musisz wiedzieć. Ale może to pomoże wyjaśnić trochę więcej:

dwie rzeczy , które musisz zrobić:

1. Sprawdź dane formularza.

Jak odpowiedź Jonathana Hobbsa pokazuje bardzo wyraźnie, wybór elementu html dla wprowadzania formularza nie robi dla ciebie żadnego wiarygodnego filtrowania.

Walidacja jest zwykle wykonywana w sposób, który nie zmienia danych, ale pokazuje formularz ponownie, z polami oznaczonymi jako " Proszę popraw to".

Większość frameworków i CMSE ma konstruktorów formularzy, które pomogą Ci w tym zadaniu. I nie tylko, pomagają również przeciwko CSRF (lub "XSRF"), który jest inną formą ataku.

2. Dezaktywacja / Escape zmiennych w poleceniach SQL..

.. lub pozwól przygotowanym wypowiedziom wykonać zadanie za Ciebie.

Jeśli budujesz (moje)polecenie SQL z dowolnymi zmiennymi, podanymi przez użytkownika lub nie, musisz uciec i zacytować te zmienne.

Ogólnie rzecz biorąc, każda taka zmienna, którą wstawiasz Instrukcja MySQL powinna być albo ciągiem znaków, albo czymś, co PHP może niezawodnie przekształcić w ciąg znaków, który może strawić MySQL. Na przykład liczby.

W przypadku ciągów znaków, musisz wybrać jedną z kilku metod, aby uciec od ciągu znaków, to znaczy, zastąpić wszelkie znaki, które mogłyby mieć skutki uboczne w MySQL.

  • w starej szkole MySQL + PHP, mysql_real_escape_string() wykonuje zadanie. Problem polega na tym, że jest zbyt łatwo zapomnieć, więc bezwzględnie należy użyć przygotowanych deklaracje lub kwerendy.
  • W MySQLi można używać gotowych instrukcji.
  • Większość frameworków i CMSE dostarcza konstruktorów zapytań, które pomagają w tym zadaniu.

Jeśli masz do czynienia z liczbą, możesz pominąć znaki specjalne i cudzysłowy(dlatego przygotowane instrukcje pozwalają określić typ).

Ważne jest, aby zwrócić uwagę, że unikasz zmiennych dla instrukcji SQL, a nie dla samej bazy danych . Baza danych będzie przechowywać oryginalny ciąg znaków, ale instrukcja wymaga wersji z klauzulą Escape.

Co się stanie, jeśli pominiesz jedną z nich?

Jeśli nie używasz walidacji formularza , ale dezaktywujesz dane wejściowe SQL, możesz zobaczyć wiele złych rzeczy, ale nie zobaczysz SQL injection! (*)

Po pierwsze, może przenieść Twoją aplikację do stanu, na który nie planowałeś. Np. jeśli chcesz obliczyć średni wiek wszystkich użytkowników, ale jeden użytkownik podał "aljkdfaqer" dla wieku, Twoje obliczenie będzie porażka.

Po drugie, mogą występować różnego rodzaju inne ataki iniekcyjne, które należy wziąć pod uwagę: np. dane wejściowe użytkownika mogą zawierać javascript lub inne rzeczy.

Nadal mogą występować problemy z bazą danych: np. jeśli pole (kolumna tabeli bazy danych) jest ograniczone do 255 znaków, a łańcuch jest dłuższy. Lub jeśli pole akceptuje tylko liczby, a zamiast tego próbujesz zapisać nieliczbowy ciąg znaków. Ale to nie jest "Wtrysk", to jest po prostu " rozbicie zastosowanie".

Ale nawet jeśli masz wolne pole tekstowe, w którym zezwalasz na dowolne dane wejściowe bez walidacji, nadal możesz zapisać to w bazie danych tak po prostu, jeśli poprawnie go unikniesz, gdy przejdzie do instrukcji bazy danych. Problem pojawia się, gdy chcesz użyć tego Sznurka gdzieś.

(*) albo to byłoby coś naprawdę egzotycznego.

Jeśli nie ukrywasz zmiennych dla poleceń SQL , ale walidujesz dane wejściowe formularza, nadal możesz zobaczyć złe rzeczy dzieje się.

Po pierwsze, ryzykujesz, że gdy zapiszesz dane do bazy danych i załadujesz je ponownie, nie będą to już te same dane, "utracone w tłumaczeniu".

Po drugie, może to spowodować niepoprawne polecenia SQL, a tym samym spowodować awarię aplikacji. Np. jeśli jakakolwiek zmienna zawiera cudzysłów lub podwójny znak cudzysłowu, w zależności od tego, jakiego typu cudzysłowu użyjesz, otrzymasz niepoprawną instrukcję MySQL.

Po trzecie, nadal może powodować SQL injection.

Jeśli dane wejściowe użytkownika z formularzy są już przefiltrowane / zwalidowane, celowe SQL injection może stać się mniej prawdopodobne, jeśli Dane wejściowe zostaną zredukowane do zakodowanej listy opcji lub ograniczone do liczb. Ale każde wolne wprowadzanie tekstu może być używane do SQL injection, jeśli nie poprawnie unikniesz zmiennych w instrukcjach SQL.

I nawet jeśli nie masz żadnych danych wejściowych, nadal możesz mieć ciągi znaków ze wszystkich źródeł: odczytywane z systemu plików, zeskrobywane z Internetu itp. Nikt nie może zagwarantować, że te sznurki są bezpieczne.

 7
Author: donquixote,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:25

Twoja przeglądarka internetowa nie "wie", że odbiera stronę z php, widzi tylko html. A warstwa http wie jeszcze mniej. Musisz być w stanie obsłużyć prawie każdy rodzaj wejścia, które może przekroczyć warstwę http(na szczęście dla większości wejściowych php już daje błąd). Jeśli próbujesz zapobiec złośliwym żądaniom, które psują Twój db, musisz założyć, że facet po drugiej stronie wie, co robi i że nie ogranicza się do tego, co możesz zobaczyć w Twoim db przeglądarka w normalnych okolicznościach(nie wspominając o tym, co można majstrować z narzędzi programistycznych przeglądarki). Tak więc tak, musisz zaspokoić wszelkie dane wejściowe z rozwijanego menu, ale dla większości danych wejściowych możesz podać błąd.

 6
Author: Nameless One,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 15:33:02

Fakt, że ograniczyłeś użytkownika do używania tylko wartości z określonej listy rozwijanej, jest nieistotny. Użytkownik techniczny może przechwycić żądanie http wysłane do serwera, zanim opuści jego sieć, zmienić je za pomocą narzędzia, takiego jak lokalny serwer proxy, a następnie kontynuować je po drodze. Używając zmienionego żądania, mogą wysyłać wartości parametrów, które nie są tymi, które zostały określone na rozwijanej liście. Deweloperzy muszą mieć nastawienie, że ograniczenia klienta są często bez znaczenia, bo wszystko na kliencie może być zmienione. Walidacja serwera jest wymagana w każdym punkcie, który wprowadza dane Klienta. Atakujący polegają na naiwności deweloperów w tym jedynym aspekcie.

 6
Author: Jason Higgins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 19:19:17

Najlepiej jest użyć parametryzowanego zapytania w celu zapewnienia przed SQL injection. W takim przypadku wygląd zapytania będzie następujący:

SELECT * FROM table WHERE size = ?

Gdy dostarczysz zapytanie takie jak powyższe z tekstem, który nie jest zweryfikowany pod względem integralności (dane wejściowe nie są weryfikowane na serwerze) i zawiera kod SQL injection, zostanie on poprawnie obsługiwany. Innymi słowy, żądanie spowoduje coś takiego w warstwie bazy danych:

SELECT * FROM table WHERE size = 'DROP table;'

To po prostu wybierze 0 wyników jako zwraca, co sprawi, że zapytanie będzie nieskuteczne w rzeczywistości wyrządzając szkodę bazie danych bez potrzeby białej listy, weryfikacji lub innych technik. Należy pamiętać, że odpowiedzialny programista wykonuje zabezpieczenia w warstwach i często weryfikuje je oprócz parametryzowania zapytań. Istnieje jednak bardzo niewiele powodów, aby nie parametryzować zapytań z perspektywy wydajności, a bezpieczeństwo dodane przez tę praktykę jest dobrym powodem do zapoznania się z zapytania parametryzowane.

 5
Author: Dan Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 20:31:15

Cokolwiek zostanie przesłane z twojego formularza, trafia na twój serwer jako tekst przez przewody. Nic nie powstrzymuje nikogo przed stworzeniem bota, który naśladuje klienta lub wpisuje go z terminala, jeśli chce. Nigdy nie zakładaj, że ponieważ zaprogramowałeś klienta, będzie działał tak, jak myślisz. To jest naprawdę łatwe do sfałszowania.

Przykład tego, co może i będzie się działo, gdy zaufasz klientowi.

 4
Author: GenericJam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-22 18:26:29

Haker może całkowicie ominąć przeglądarkę, włączając sprawdzanie formularzy Javascript, wysyłając żądanie za pomocą Telnetu. Oczywiście spojrzy na kod twojej strony html, aby uzyskać nazwy pól, których musi użyć, ale od tego czasu będzie to "wszystko idzie" dla niego. Musisz więc sprawdzić wszystkie wartości przesłane na serwerze tak, jakby nie pochodziły z twojej strony html.

 4
Author: user1452686,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-25 22:45:10