- Przeprowadziliśmy badanie w celu wykorzystania istniejących rozwiązań. Przetestowaliśmy trzy różne środowiska testowe do ćwiczenia ataków SQL Injection:
- OWASP WebGoat i OWASP Zap - kompleksowy przewodnik po testowaniu bezpieczeństwa aplikacji internetowych i usług internetowych, spośród których jest również SQL Injection.
- SQL Injection Exercise - wprowadzenie do bezpiecznego programowania. Niestety nie udało się sprawdzić, ponieważ maszyna wirtualna, podana w rozwiązaniu, nie uruchamia się skutecznie.
- Security of Information and Organizations - SQL Injection - kurs "Bezpieczeństwa informacji i organizacji" od portugalskiego profesora João Paulo Barraca. Obszerny kurs laboratoriów bezpieczeństwa, które również pokrywają temat SQL Injection.
- Stwierdziliśmy, że zrobimy własne rozwiązanie, które byłoby podobnym do trzeciego rozwiązania "Security of Information and Organizations - SQL Injection".
- Zakupiliśmy i odpowiednio przygotowaliśmy Virtual Private Server (VPS) w systemie OVHCloud, na nim został zainstalowany system Ubuntu.
- Utworzyliśmy konta dla użytkowników (Jakub, Vitalii), ustawiliśmy uwierzytelnianie tylko za pomocą szyfrowania asymetrycznego algorytmami RSA lub Ed25519.
- Zainstalowaliśmy i odpowiednio skonfigurowaliśmy system bazodanowy PostgreSQL na VPS, następnie pobraliśmy oraz odpowiednio zmodyfikowaliśmy i zainstalowaliśmy przykładową bazę danych (Dell Store 2).
- Zmodyfikowaliśmy w tabeli customers kolumnę "password" w taki sposób, aby zapisywane były hasła w postaci haszowanej. Znaleźliśmy zbiór najczęściej wykorzystywanych haseł i przypisaliśmy go dla wszystkich 20 000 użytkowników.
- Przygotowaliśmy kod w języku Python do łączenia się z bazą danych oraz funkcję przywrócenia bazy do stanu początkowego.
- Przygotowaliśmy podatny na ataki (SQL Injection) kod w języku Python do wywoływania zapytań SQL.
- Za pomocą biblioteki Streamlit przygotowaliśmy stronę internetową - wizualny interfejs dla użytkownika. Strona zawiera trzy środowiska do przeprowadzania ataków:
- Panel logowania - jeden z najczęściej wykorzystywanych miejsc do ataku SQL Injection.
- Panel rejestracji - pozwala wprowadzać nowych użytkowników do bazy danych oraz przeprowadzać ataki wykorzystując pola tekstowe.
- Wyszukiwarka filmów - chcieliśmy pokazać jakie ataki można wykonywać, wykorzystując tabele.
- Na stronie internetowej został dodany krótki poradnik na temat ataków SQL Injection z przykładami.
- Na każdym panelu zostały dodane podpowiedzi, ułatwiające użytkownikowi przeprowadzenie ataku.
- Jeżeli użytkownik specjalnie czy przez przypadek zepsuję bazę danych, to w każdym momencie, korzystając z panelu bocznego może przywrócić bazę do stanu początkowego.
- Został przygotowany również poradnik, pokazujący w jaki sposób trzeba zmienić kod w języku Python, aby nie był już podatny na podstawowe ataki SQL Injection.
Łączenie się z bazą danych PostgreSQL i uruchomienie wszystkich kwerend w Pythonie wykonuje się w następujący sposób:
import psycopg2
connection = psycopg2.connect(
host="127.0.0.1",
database="dellstore2",
user="sqlinjection",
password="3FS-DI"
)
with connection.cursor() as cursor:
cursor.execute("SELECT username, password FROM customers;")
print(cursor.fetchone())
# ('user1', '15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225')
Jedyne miejsce podatne na ataki SQL Injection w tym kodzie znajduje się w linijce dziesiątej:
cursor.execute("SELECT username, password FROM customers;")
Jeżeli nasze zapytanie przyjmuje jakieś dane od użytkownika, to nie mogą one być po prostu wklejone bez żadnej weryfikacji. Poniżej jest podany BŁĘDNY sposób przyjmowania argumentów użytkownika:
username = "user1"
with connection.cursor() as cursor:
cursor.execute(f"SELECT firstname, lastname "
f"FROM customers WHERE username='{username}';")
print(cursor.fetchone())
Czemu? A co się stanie, jeżeli zamiast "user1"
użytkownik poda "user1'; SELECT * FROM customers; --"
? Wykona się następne polecenie SQL:
SELECT firstname, lastname FROM customers WHERE username='user1';
SELECT * FROM customers;
--*"`
W takim przypadku użytkownik może dostać dowolne dane z bazy danych. Poprawnym zabezpieczeniem przed atakiem SQL Injection jest wykorzystanie specjalnych filtrów, które sprawdzają wartości otrzymane od użytkownika. W przypadku PostgreSQL i Pythona najprostszym rozwiązaniem jest użycie domyślnie dostępnej funkcji przekazywania parametrów:
username = "user1'; SELECT * FROM customers; --"
with connection.cursor() as cursor:
cursor.execute("SELECT firstname, lastname "
"FROM customers WHERE username=%(checked_username)s;",
{"checked_username": username})
print(cursor.fetchone())
# None
Jak widzimy, filtr skutecznie zablokował możliwość wykonania takiego polecenia i zwróciło ono wartość None
.
username: sqlinjection
password: 3FS-DI
name: dbspace
location: /var/lib/postgresql/data
name: dellstore2
git clone https://github.com/FrightenedFox/psb-project-sql-injection
cd psb-project-sql-injection
pip install -e .
streamlit run psb_project/SQL_Injection.py
Aby uruchomić aplikacje i zamknąć konsolę (instrukcja stąd):
streamlit run psb_project/SQL_Injection.py &
disown %1
gdzie 1
oznacza numer procesu w tle, można otrzymać wpisując jobs -l
.
-
Poprawić relacje w bazie danych - Podmienić hasła
- Automatycznie wyczyszczenie na panelu logowania (zmiana logowanie/rejestreacja)
- Inna nazwa przycisku załóż konto
- Zmienić "niepoprawna nazwa" na "taki użytkownik już istnieje"
- Pozwolić początek pracy z dowolnej strony
- Podać w Streamlit/dokumentacji pierwsze 10 wierszy z pliku
psb_project/dellstore2/database_readable_passwords.csv
, żeby można było testować hasła rzeczywistych już istniejących użytkowników. Można również powiedzieć, że hasła zostały przydzielone użytkownikom w kolejności zmniejszenia się ich popularności (user1 - najbardziej popularne, user20000 - najmniej popularne); jednak nie są to najpopularjniejsze hasła (po prostu losowo wybrane ze zbioru danych najpopularnieszych). - Opisać co trzeba zmienić w kodzie, aby nie był podatny na ataki SQL Injection.
- (jako pomysł, jeżeli będzie mało tego, co zrobiliśmy) Dodać przełącznik na tryb zabezpieczony, w którym kod już jest dobrze napisany i nie da się zaatakować przez SQL Inection.
- Przygotować nowe zapytania do bazy (zabezpieczone).
- Połączyć z frontendem.
- Na zakładce "Wyszukiwarka filmów" raczej dobrze by było podnieść tą wskazówke SQL Inection do góry, bo na dole tam nikt jej nie znajdzie.
- Wskazówka na stronie logowania nie działa, bo używamy funkcji haszującej.