Wstrzyknięcie SQL

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

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 jak addslashes() 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:

 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=1 Lub UNION SELECT już 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.

  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, np http://localhost/dvwa w Twojej przeglądarce.
plik
  • Zaloguj się do DVWA przy użyciu domyślnych danych uwierzytelniających: admin / password .
plik
  • Przejdź do zakładki Bezpieczeństwo DVWA i ustaw poziom zabezpieczeń na niski. Dzięki temu luki będą łatwe do wykorzystania.
plik

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 tak SELECT * FROM users WHERE id = 'user_input'

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

Ź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

Zapytanie staje się:

 SELECT * FROM users WHERE id = ''';  

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

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ą plik UNION operator łączący wyniki dwóch lub więcej SELECT instrukcje w jeden zestaw wyników. Może to pozwolić im na wyodrębnienie informacji z innych tabel w bazie danych. The UNION operatora 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 : UNION operator służy do łączenia zestawu wyników składającego się z dwóch lub więcej SELECT oświadczenia.

  • Każdy SELECT oświadczenie w środku UNION musi 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 z UNION Słowo kluczowe umożliwiające odkrycie liczby kolumn

Aby skorzystać z UNION słowo kluczowe (częsty kolejny krok), musisz znać liczbę kolumn w oryginalnym zapytaniu. Można się tego dowiedzieć korzystając z ORDER BY klauzula

  • Spróbuj posortować wyniki według kolumn
  1   :    1 ORDER BY 1   .   
  • Składać. Powinno działać.
plik

Ź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
  • Kontynuuj zwiększanie, aż pojawi się błąd. Na przykład 1 ORDER BY 4 moż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ę (np SLEEP() 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 plikiem user_input pole, 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 wie 1=1 jest PRAWDA oświadczenie.

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

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

plik

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.

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.