Co to jest wstrzykiwanie SQL i jak zapobiegać aplikacjom PHP?

Więc uważasz, że Twoja baza danych SQL jest wydajna i bezpieczna przed natychmiastowym zniszczeniem? Cóż, SQL Injection się nie zgadza!


Tak, mówimy o natychmiastowym zniszczeniu, ponieważ nie chcę otwierać tego artykułu ze zwykłą kiepską terminologią „zaostrzania bezpieczeństwa” i „zapobiegania złośliwemu dostępowi”. SQL Injection to tak stara sztuczka w książce, że każdy, każdy programista, wie o tym bardzo dobrze i doskonale wie, jak temu zapobiec. Z wyjątkiem tego jednego nieparzystego momentu, gdy się wymykają, a wyniki mogą być katastrofalne.

Jeśli już wiesz, co to jest SQL Injection, możesz przejść do drugiej połowy artykułu. Ale dla tych, którzy dopiero rozpoczynają pracę w dziedzinie tworzenia stron internetowych i marzą o przyjęciu wyższych ról, warto wprowadzić trochę wprowadzenia.

Co to jest zastrzyk SQL?

Kluczem do zrozumienia SQL Injection jest jego nazwa: SQL + Injection. Słowo „zastrzyk” nie ma tu żadnych medycznych konotacji, lecz jest używane czasownik „zastrzyk”. Te dwa słowa razem wyrażają ideę umieszczenia SQL w aplikacji internetowej.

Umieszczanie SQL w aplikacji internetowej. . . hmmm . . . Czy to nie to, co robimy? Tak, ale nie chcemy, aby atakujący prowadził naszą bazę danych. Rozumiemy to na podstawie przykładu.

Załóżmy, że budujesz typową stronę PHP dla lokalnego sklepu e-commerce, więc decydujesz się na dodanie formularza kontaktowego takiego:

Twoje imię

Twoja wiadomość

Załóżmy, że plik send_message.php przechowuje wszystko w bazie danych, aby właściciele sklepów mogli później czytać wiadomości użytkowników. Może mieć taki kod:

<?php

$ name = $ _POST [‘name’];
$ message = $ _POST [‘message’];

// sprawdź, czy ten użytkownik ma już wiadomość
mysqli_query ($ conn, "WYBIERZ * spośród wiadomości, których nazwa = $ nazwa");

// Inny kod tutaj

Więc najpierw próbujesz sprawdzić, czy ten użytkownik ma już nieprzeczytaną wiadomość. Zapytanie WYBIERZ * z wiadomości, w których nazwa = $ nazwa wydaje się dość proste, prawda?

ŹLE!

W naszej niewinności otworzyliśmy drzwi do natychmiastowego zniszczenia naszej bazy danych. Aby tak się stało, atakujący musi spełnić następujące warunki:

  • Aplikacja działa na bazie danych SQL (obecnie prawie każda aplikacja jest)
  • Bieżące połączenie z bazą danych ma uprawnienia do „edycji” i „usuwania” w bazie danych
  • Nazwy ważnych tabel można odgadnąć

Trzeci punkt oznacza, że ​​teraz, gdy osoba atakująca wie, że prowadzisz sklep e-commerce, najprawdopodobniej przechowujesz dane zamówienia w tabeli zamówień. Uzbrojony w to wszystko, co atakujący musi zrobić, to podać jako swoją nazwę:

Joe; obcinać zamówienia ;? Tak jest! Zobaczmy, jakie będzie zapytanie, gdy zostanie wykonane przez skrypt PHP:

WYBIERZ * Z wiadomości GDZIE nazwa = Joe; obcinać zamówienia;

Okej, pierwsza część zapytania zawiera błąd składniowy (brak cudzysłowów wokół „Joe”), ale średnik zmusza silnik MySQL do rozpoczęcia interpretacji nowego: obciąć zamówienia. Tak po prostu, za jednym zamachem cała historia zamówień zniknęła!

Teraz, gdy wiesz już, jak działa SQL Injection, czas zastanowić się, jak go zatrzymać. Dwa warunki, które należy spełnić, aby pomyślnie wstrzyknąć SQL, to:

  1. Skrypt PHP powinien mieć uprawnienia do modyfikowania / usuwania bazy danych. Myślę, że dotyczy to wszystkich aplikacji i nie będziesz w stanie uczynić swoich aplikacji tylko do odczytu. Gu I zgadnij, co, nawet jeśli usuniemy wszystkie uprawnienia do modyfikowania, wstrzyknięcie SQL może nadal pozwolić komuś na uruchomienie zapytań SELECT i wyświetlenie całej bazy danych, w tym poufnych danych. Innymi słowy, obniżenie poziomu dostępu do bazy danych nie działa, a Twoja aplikacja i tak tego potrzebuje.
  2. Dane użytkownika są przetwarzane. Jedynym sposobem, w jaki może działać zastrzyk SQL, jest akceptowanie danych od użytkowników. Ponownie nie jest praktyczne zatrzymywanie wszystkich danych wejściowych do aplikacji tylko dlatego, że obawiasz się wstrzyknięcia SQL.

Zapobieganie iniekcji SQL w PHP

Teraz, biorąc pod uwagę, że połączenia z bazą danych, zapytania i dane wejściowe użytkownika są częścią życia, w jaki sposób zapobiegamy wstrzykiwaniu SQL? Na szczęście jest to dość proste i można to zrobić na dwa sposoby: 1) oczyścić dane wejściowe użytkownika i 2) użyć przygotowanych instrukcji.

Wyczyść dane wprowadzone przez użytkownika

Jeśli używasz starszej wersji PHP (5.5 lub nowszej, a często dzieje się to na hostingu współdzielonym), mądrze jest uruchomić wszystkie dane wejściowe użytkownika za pomocą funkcji o nazwie mysql_real_escape_string (). Zasadniczo to, co robi, usuwa wszystkie znaki specjalne w ciągu, aby stracić swoje znaczenie, gdy są używane przez bazę danych.

Na przykład, jeśli masz ciąg taki jak jestem ciągiem, atakujący może użyć pojedynczego cudzysłowu („”) do manipulowania tworzonym zapytaniem do bazy danych i spowodowania wstrzyknięcia SQL. Uruchomienie go za pomocą mysql_real_escape_string () powoduje, że jestem ciągiem, który dodaje odwrotny ukośnik do pojedynczego cudzysłowu, unikając go. W rezultacie cały ciąg znaków jest teraz przekazywany do bazy danych jako nieszkodliwy ciąg, zamiast być w stanie uczestniczyć w manipulowaniu zapytaniami.

Podejście to ma jedną wadę: jest to naprawdę bardzo stara technika, która jest zgodna ze starszymi formami dostępu do bazy danych w PHP. Od PHP 7 ta funkcja już nawet nie istnieje, co prowadzi nas do naszego następnego rozwiązania.

Używaj przygotowanych wyciągów

Przygotowane instrukcje są sposobem na bezpieczniejsze i niezawodne zapytania do bazy danych. Chodzi o to, że zamiast wysyłania surowego zapytania do bazy danych, najpierw informujemy bazę danych o strukturze zapytania, które wyślemy. To właśnie rozumiemy przez „przygotowanie” oświadczenia. Po przygotowaniu instrukcji przekazujemy informacje jako sparametryzowane dane wejściowe, dzięki czemu baza danych może „wypełnić luki” poprzez podłączenie danych wejściowych do struktury zapytania, którą wcześniej przesłaliśmy. Odrzuca to wszelką specjalną moc, jaką mogą mieć dane wejściowe, powodując, że są one traktowane jak zwykłe zmienne (lub ładunki, jeśli chcesz) w całym procesie. Oto jak wyglądają przygotowane oświadczenia:

<?php
$ nazwa_serwera = "Lokalny Gospodarz";
$ nazwa użytkownika = "Nazwa Użytkownika";
$ hasło = "hasło";
$ dbname = "myDB";

// Utwórz połączenie
$ conn = nowy mysqli ($ nazwa serwera, $ nazwa użytkownika, $ hasło, $ dbname);

// Sprawdź połączenie
if ($ conn->connect_error) {
umierać("Połączenie nieudane: " . $ conn->błąd połączenia);
}

// przygotuj i zwiąż
$ stmt = $ conn->przygotować("WSTAWIĆ DO MyGuests (imię, nazwisko, adres e-mail) WARTOŚCI (?,?,?)");
$ stmt->bind_param ("sss", $ imię, $ nazwisko, $ email);

// ustaw parametry i uruchom
$ imię = "Jan";
$ nazwisko = "Łania";
$ email = "[chroniony e-mailem]";
$ stmt->wykonać();

$ imię = "Mary";
$ nazwisko = "Moe";
$ email = "[chroniony e-mailem]";
$ stmt->wykonać();

$ imię = "Julie";
$ nazwisko = "Dooley";
$ email = "[chroniony e-mailem]";
$ stmt->wykonać();

Echo "Nowe rekordy zostały utworzone pomyślnie";

$ stmt->blisko();
$ conn->blisko();
?>

Wiem, że proces ten wydaje się niepotrzebnie skomplikowany, jeśli dopiero zaczynasz przygotowywać wypowiedzi, ale koncepcja jest warta wysiłku. Oto miłe wprowadzenie do tego.

Dla tych, którzy już znają rozszerzenie PDO PHP i używają go do tworzenia przygotowanych instrukcji, mam małą radę.

Ostrzeżenie: zachowaj ostrożność podczas konfigurowania PDO

Używając PDO do dostępu do bazy danych, możemy wpaść w fałszywe poczucie bezpieczeństwa. „Ach, cóż, używam PDO. Teraz nie muszę myśleć o niczym innym ”- tak właśnie wygląda nasze myślenie. To prawda, że ​​PDO (lub instrukcje przygotowane przez MySQLi) wystarcza, aby zapobiec wszelkiego rodzaju atakom typu SQL injection, ale należy zachować ostrożność podczas jego konfigurowania. Zwykle po prostu kopiuj i wklej kod z samouczków lub wcześniejszych projektów i przejdź dalej, ale to ustawienie może cofnąć wszystko:

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, prawda);

To ustawienie ma na celu poinformowanie PDO o emulacji przygotowanych instrukcji, zamiast faktycznego korzystania z funkcji przygotowanych instrukcji w bazie danych. W związku z tym PHP wysyła proste ciągi zapytań do bazy danych, nawet jeśli kod wygląda na to, że tworzy przygotowane instrukcje i ustawia parametry i tak dalej. Innymi słowy, jesteś tak samo podatny na wstrzykiwanie SQL, jak wcześniej. ��

Rozwiązanie jest proste: upewnij się, że ta emulacja jest ustawiona na false.

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, false);

Teraz skrypt PHP jest zmuszony do używania przygotowanych instrukcji na poziomie bazy danych, co zapobiega wszelkiego rodzaju iniekcjom SQL.

Zapobieganie używaniu WAF

Czy wiesz, że możesz również chronić aplikacje internetowe przed wstrzyknięciem SQL za pomocą WAF (zapory sieciowej)?

Cóż, nie tylko wstrzyknięcie SQL, ale wiele innych luk w warstwie 7, takich jak skrypty między witrynami, zepsute uwierzytelnianie, fałszowanie witryn, ujawnianie danych itp. Możesz użyć hostingu własnego, takiego jak Mod Security lub opartego na chmurze, jak poniżej.

Wstrzykiwanie SQL i nowoczesne frameworki PHP

Wstrzykiwanie SQL jest tak powszechne, tak łatwe, tak frustrujące i tak niebezpieczne, że wszystkie nowoczesne frameworki PHP są wbudowane w środki zaradcze. Na przykład w WordPress mamy $ wpdb->funkcja przygotuj (), a jeśli używasz frameworka MVC, to robi to dla ciebie brudną robotę i nawet nie musisz myśleć o zapobieganiu wstrzykiwaniu SQL. To trochę denerwujące, że w WordPress musisz jawnie przygotowywać oświadczenia, ale hej, mówimy o WordPressie. ��

W każdym razie chodzi mi o to, że współczesna rasa programistów internetowych nie musi myśleć o wstrzykiwaniu SQL, w wyniku czego nie są nawet świadomi takiej możliwości. W związku z tym, nawet jeśli pozostawiają otwarte backdoor w aplikacji (być może jest to parametr zapytania $ _GET i stare nawyki odpalania nieczytelnego zapytania), wyniki mogą być katastrofalne. Dlatego zawsze lepiej jest poświęcić trochę czasu, aby zanurzyć się głębiej w fundamenty.

Wniosek

SQL Injection to bardzo paskudny atak na aplikację internetową, ale łatwo go uniknąć. Jak widzieliśmy w tym artykule, ostrożność podczas przetwarzania danych wejściowych użytkownika (nawiasem mówiąc, SQL Injection nie jest jedynym zagrożeniem, jakie niesie ze sobą obsługa danych wejściowych użytkownika) i zapytania do bazy danych to wszystko. To powiedziawszy, nie zawsze pracujemy nad bezpieczeństwem frameworka sieciowego, więc lepiej być świadomym tego rodzaju ataków i nie dać się nabrać.

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map