logo

Wstrzyknięcie SQL

Wstrzykiwanie SQL to luka w zabezpieczeniach aplikacji internetowych, polegająca na tym, że osoby atakujące wstawiają szkodliwy kod SQL poprzez dane wejściowe użytkownika. Może to pozwolić im na dostęp do poufnej zawartości bazy danych i zmianę danych, a nawet przejąć kontrolę nad systemem. Aby zapewnić bezpieczeństwo aplikacji internetowych, warto wiedzieć o wstrzykiwaniu SQL.

SQL Injection (SQLi) to luka w zabezpieczeniach występująca, gdy osoba atakująca może manipulować zapytaniami do bazy danych aplikacji internetowej, wstawiając złośliwy kod SQL do pól wejściowych użytkownika. Te wprowadzone zapytania mogą manipulować podstawową bazą danych w celu pobrania modyfikacji lub usunięcia poufnych danych. W niektórych przypadkach napastnicy mogą nawet eskalować uprawnienia, uzyskując pełną kontrolę nad bazą danych lub serwerem.



wtrysk sql' title=

Przykład ze świata rzeczywistego:

W 2019 r. doszło do naruszenia bezpieczeństwa danych w Capital One spowodowanego źle skonfigurowaną aplikacją internetową, która umożliwiła osobie atakującej wykorzystanie luki w zabezpieczeniach polegającej na wstrzyknięciu SQL. Doprowadziło to do wycieku danych osobowych ponad 100 milionów klientów, w tym imion, adresów i ocen zdolności kredytowej.

Poziom bezpieczeństwa wstrzykiwania SQL

DVWA zapewnia cztery poziomy bezpieczeństwa dla SQL Injection, aby pomóc uczniom zobaczyć, jak różne zabezpieczenia wpływają na ataki:



1. Niskie bezpieczeństwo

Aplikacja pobiera Twoje dane i bezpośrednio umieszcza je w zapytaniu SQL, bez filtrowania.

$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';
  • Wstępowanie ': Przerywa zapytanie i powoduje, że baza danych zgłasza błąd wskazujący, że jest podatna na ataki.
  • Wstępowanie 1' OR '1'='1: Oszukuje zapytanie, aby zawsze było prawdziwe, więc zwróceni zostaną wszyscy użytkownicy.
  • Wstępowanie 1' UNION SELECT user password FROM users--: Dołącza do innego zapytania, aby pobrać ukryte dane, takie jak nazwy użytkowników i hasła.

2. Średni poziom bezpieczeństwa

Aplikacja stosuje podstawową dezynfekcję danych wejściowych za pomocą takich funkcji jakaddslashes()uciec'.

$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';

Jak można zaatakować:



Proste'zastrzyk już nie będzie działał (ponieważ staje się').

Jednak osoby atakujące nadal mogą ominąć tę metodę, stosując wstrzykiwanie numeryczne (ponieważ liczby nie wymagają cudzysłowów).
Przykład:

maszynopis data godzina
1 OR 1=1

To nadal zwraca wszystkie rekordy.

3. Wysokie bezpieczeństwo

Aplikacja korzysta z przygotowanych instrukcji (sparametryzowanych zapytań), aby bezpiecznie obsługiwać dane wprowadzane przez użytkownika.

$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);

Atak:

Próby jak' OR 1=1LubUNION SELECTjuż nie pracować.

Zapytanie traktuje wszystkie dane wejściowe jako dane, a nie kod SQL.

Rodzaje iniekcji SQL

Istnieją różne typy wstrzykiwania SQL

1. Wstrzykiwanie SQL oparte na błędach

Wstrzyknięcie SQL oparte na błędach to rodzaj wewnętrznego wstrzyknięcia SQL, podczas którego osoba atakująca celowo powoduje, że baza danych wygeneruje komunikat o błędzie. Osoba atakująca następnie analizuje ten komunikat o błędzie, aby uzyskać cenne informacje o strukturze bazy danych, takie jak nazwy tabel i nazwy kolumn, które można wykorzystać do przeprowadzenia dalszych, bardziej precyzyjnych ataków.

Jak to działa

Celem tego ataku są aplikacje, które zamiast wyświetlać ogólne komunikaty, ujawniają nieprzetworzone błędy baz danych. Wstrzykując złośliwe dane wejściowe, które łamią składnię SQL, atakujący powodują te błędy i zdobywają cenne wskazówki na temat struktury bazy danych.

jak wstrzyknąć próbną klasę abstrakcyjną
  1. Zidentyfikuj podatne dane wejściowe: Osoba atakująca znajduje pole wejściowe, takie jak pasek wyszukiwania lub parametr adresu URL, które bezpośrednio wchodzi w interakcję z bazą danych bez odpowiedniego oczyszczenia danych wejściowych.
  2. Wstrzyknij złośliwy ładunek: Osoba atakująca wprowadza znak specjalny (np. pojedynczy cudzysłów') lub funkcję, o której wiadomo, że powoduje błąd bazy danych.
  3. Przeanalizuj błąd: Baza danych nie może przetworzyć zniekształconego zapytania, zwraca szczegółowy komunikat o błędzie. Ta wiadomość może ujawnić kluczowe informacje, takie jak:
    • System baz danych (np. MySQL Oracle SQL Server).
    • Wersja bazy danych.
    • Wykonywane jest pełne zapytanie SQL.
    • Specyficzne błędy składniowe, które można wykorzystać do zrozumienia nazw tabel lub kolumn.
  4. Udoskonal atak: Korzystając z informacji zebranych w komunikacie o błędzie, osoba atakująca może udoskonalić swój ładunek, aby wyodrębnić więcej danych, takich jak nazwy użytkowników i hasła.

Przykład:

Krok 1: Skonfiguruj swoje środowisko

  • Uruchom DVWA. Dostęp do niego zwykle można uzyskać, przechodząc do adresu URL, nphttp://localhost/dvwaw Twojej przeglądarce.
plik' loading='lazy' title=
  • Zaloguj się do DVWA przy użyciu domyślnych danych uwierzytelniających:admin/password.
plik' loading='lazy' title=
  • Przejdź do zakładki Bezpieczeństwo DVWA i ustaw poziom zabezpieczeń na niski. Dzięki temu luki będą łatwe do wykorzystania.
plik' loading='lazy' title=

Krok 2: Zidentyfikuj lukę

Strona SQL Injection zawiera proste pole wprowadzania, w którym można wprowadzić identyfikator użytkownika. Zapytanie zaplecza prawdopodobnie wygląda mniej więcej takSELECT * FROM users WHERE id = 'user_input'

  • Wprowadź prawidłowy identyfikator, np1w polu wprowadzania i kliknij przycisk „Prześlij”. Powinieneś zobaczyć szczegóły użytkownika o identyfikatorze 1.
plik' loading='lazy' title=

Źródło wtrysku SQL

PHP
 $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?>
  • Teraz spróbuj przerwać zapytanie. Wprowadź pojedynczy cudzysłów'w polu wprowadzania i prześlij.
plik' loading='lazy' title=

Zapytanie staje się:

SELECT * FROM users WHERE id = ''';

Tutaj baza danych widzi dodatkowy cytat i nie wie, jak dokończyć zapytanie.

dzielenie ciągów C++

Zamiast pokazywać szczegóły użytkownika, aplikacja zwróci błąd SQL (coś w rodzaju „Wystąpił błąd w składni SQL…”).

Nazywa się to wstrzykiwaniem SQL opartym na błędach, ponieważ:

  • Osoba atakująca wysyła nieprawidłowe dane wejściowe (')
  • Baza danych wyrzuca błąd
  • Ten błąd powoduje wyciek przydatnych informacji o bazie danych (takich jak typ bazy danych, liczba struktur kolumn itp.)

2. Wstrzykiwanie SQL oparte na Unii

Wstrzykiwanie SQL oparte na Unii to technika, w której atakujący wykorzystują plikUNIONoperator łączący wyniki dwóch lub więcejSELECTinstrukcje w jeden zestaw wyników. Może to pozwolić im na wyodrębnienie informacji z innych tabel w bazie danych. TheUNIONoperatora można użyć tylko wtedy, gdy:

  • Obydwa zapytania mają tę samą liczbę kolumn
  • Kolumny mają podobne typy danych
  • Kolumny są w tej samej kolejności

Operator UNII :UNIONoperator służy do łączenia zestawu wyników składającego się z dwóch lub więcejSELECToświadczenia.

  • KażdySELECToświadczenie w środkuUNIONmusi mieć tę samą liczbę kolumn
  • Kolumny muszą mieć podobne typy danych
  • Kolumny muszą być w tej samej kolejności
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2

Przykład:

Krok 1: Najpierw musimy znaleźć liczbę kolumn istniejącej tabeli w witrynie, aby wstrzyknąć SQL Injection w oparciu o UNION:

Strona SQL Injection zawiera proste pole wprowadzania, w którym można wprowadzić identyfikator użytkownika. Zapytanie zaplecza prawdopodobnie wygląda mniej więcej tak

 SELECT * FROM users WHERE id = 'user_input'

Teraz spróbuj przerwać zapytanie. Wprowadź pojedynczy cudzysłów'w polu wprowadzania i prześlij.

Jeśli aplikacja jest podatna na ataki, otrzymasz szczegółowy komunikat o błędzie. Może to wyglądać mniej więcej tak:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

Krok 2: Skorzystaj zUNIONSłowo kluczowe umożliwiające odkrycie liczby kolumn

Aby skorzystać zUNIONsłowo kluczowe (częsty kolejny krok), musisz znać liczbę kolumn w oryginalnym zapytaniu. Można się tego dowiedzieć korzystając zORDER BYklauzula

„abc” w liczbach
  • Spróbuj posortować wyniki według kolumn
1: 1 ORDER BY 1. 
  • Składać. Powinno działać.
plik' loading='lazy' title=

Źródło wtrysku SQL

PHP
 if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?>
  • Zwiększ liczbę:
 1 ORDER BY 2. 

Składać. Powinno działać.

plik' loading='lazy' title=
  • Kontynuuj zwiększanie, aż pojawi się błąd. Na przykład1 ORDER BY 4może ci dać:Unknown column '4' in 'order clause'
  • Oznacza to, że zapytanie ma 3 kolumny.

3. Wstrzykiwanie SQL metodą ślepej próby

Ślepy wtrysk SQL występuje, gdy atakujący nie mogą zobaczyć wyników zapytania bezpośrednio na stronie internetowej. Zamiast tego wnioskują informacje na podstawie subtelnych zmian w zachowaniu aplikacji lub czasie reakcji. Chociaż wolniejszy i bardziej żmudny niż klasyczny SQLi, może być równie skuteczny.

Zamiast odzyskać dane, osoba atakująca wyciąga wnioski na podstawie obserwacji zachowania strony internetowej. Zwykle odbywa się to na jeden z dwóch sposobów:

  1. Ślepy SQLi oparty na wartościach logicznych: Osoba atakująca wprowadza zapytanie SQL, które zwraca a PRAWDA Lub FAŁSZ wynik. Odpowiedź aplikacji internetowej zmienia się w zależności od tego, czy zapytanie jest prawdziwe, czy fałszywe. Na przykład strona może wyświetlać inny komunikat lub renderować inny układ.
  2. Ślepe SQLi oparte na czasie: Osoba atakująca wprowadza zapytanie SQL, które powoduje, że baza danych wykonuje czasochłonną akcję (npSLEEP()funkcja), jeśli warunek jest spełniony. Osoba atakująca obserwuje czas potrzebny do załadowania strony, aby określić, czy wprowadzony warunek był prawdziwy, czy fałszywy.

Przykład:

Wyobraź sobie stronę logowania, na której wpisujesz nazwę użytkownika i hasło. Aplikacja konstruuje zapytanie SQL w następujący sposób:

SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'

Ślepy zastrzyk SQL wymagałby manipulacji plikiemuser_inputpole, w którym możesz zadać pytanie bazie danych.

Zamiast uzyskać bezpośrednią odpowiedź, atakujący może spróbować czegoś takiego:

user_input = 'admin' AND 1=1; --

Jeśli strona ładuje się normalnie, atakujący o tym wie1=1jest PRAWDA oświadczenie.

user_input = 'admin' AND 1=2; --

Jeśli strona pokazuje błąd lub zachowuje się inaczej, osoba atakująca o tym wie1=2jest FAŁSZ oświadczenie.

plik' loading='lazy' title=

Używając serii pytań typu prawda/fałsz, osoba atakująca może systematycznie odgadywać i wydobywać informacje, po jednym znaku na raz. Proces można zautomatyzować, aby odgadnąć wszystko, od nazw tabel po hasła użytkowników.

Wpływ ataków typu SQL Injection

  • Nieautoryzowany dostęp do wrażliwych danych : osoby atakujące mogą odzyskać osobiste informacje finansowe lub poufne przechowywane w bazie danych.
  • Problemy z integralnością danych : osoby atakujące mogą modyfikować, usuwać lub uszkadzać krytyczne dane, wpływając na funkcjonalność aplikacji.
  • Eskalacja przywilejów : Osoby atakujące mogą ominąć mechanizmy uwierzytelniania i uzyskać uprawnienia administracyjne.
  • Przerwa w działaniu usługi : Wstrzyknięcie SQL może przeciążyć serwer, powodując pogorszenie wydajności lub awarię systemu.
  • Uszkodzenie reputacji : Udany atak może poważnie zaszkodzić reputacji organizacji, prowadząc do utraty zaufania klientów.

Zapobieganie atakom typu SQL Injection

Istnieje kilka najlepszych praktyk zapobiegania atakom polegającym na wstrzykiwaniu kodu SQL:

1. Używaj przygotowanych instrukcji i sparametryzowanych zapytań

Przygotowane instrukcje i sparametryzowane zapytania zapewniają, że dane wejściowe użytkownika są traktowane jako dane, a nie część zapytania SQL. Takie podejście eliminuje ryzyko wstrzyknięcia SQL.

Przykład w PHP (przy użyciu MySQLi):

$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();

2. Stosuj procedury składowane

Procedury składowane to predefiniowane zapytania SQL przechowywane w bazie danych. Procedury te mogą pomóc w zapobieganiu wstrzykiwaniu SQL, ponieważ nie konstruują dynamicznie zapytań SQL.

Przykład:

CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;

3. Weryfikacja danych wejściowych na białej liście

Upewnij się, że dane wejściowe użytkownika są sprawdzane przed użyciem w zapytaniach SQL. Zezwalaj tylko na określone znaki i wzorce, takie jak wprowadzanie alfanumeryczne, w polach takich jak nazwy użytkowników lub adresy e-mail.

bool do napisania Java

4. Użyj frameworków ORM

Struktury mapowania obiektowo-relacyjnego (ORM), takie jak Hibernować Lub Struktura encji może pomóc w zapobieganiu wstrzykiwaniu SQL, automatycznie obsługując generowanie zapytań, uniemożliwiając dynamiczne konstruowanie zapytań.

5. Ogranicz uprawnienia do bazy danych

Przyznaj użytkownikom minimalne wymagane uprawnienia do bazy danych. Upewnij się, że aplikacje mogą wykonywać tylko niezbędne akcje (np. WYBIERZ WSTAW) i ograniczaj uprawnienia, takie jak DROP TABLE lub ALTER.

6. Obsługa błędów

Skonfiguruj bazę danych i aplikację tak, aby nie wyświetlała użytkownikowi szczegółowych komunikatów o błędach. Zamiast tego rejestruj błędy wewnętrznie i wyświetlaj ogólne komunikaty o błędach użytkownikom końcowym.