SQL injection: nigdy nie sklejaj tekstu użytkownika w zapytanie
Zapytania na tej stronie wpisujesz celowo. W aplikacji część tekstu zapytania pochodzi z formularza, adresu URL lub API. Jeśli ten tekst wklei się do SQL, odwiedzający może zmienić, co robi polecenie. Ta strona pokazuje błąd na bazie piekarni, a potem poprawkę. To nie jest przewodnik po atakowaniu innych systemów.
Zapytanie, które miałeś na myśli
Załóżmy, że aplikacja szuka klienta po nazwisku. Zamierzony SQL filtruje tylko po tym nazwisku.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' ORDER BY customer_id;
Wynik: Ana Lopez, jeden wiersz.
Co może zrobić wklejony tekst
Jeśli aplikacja buduje polecenie jako `WHERE last_name = '` plus to, co wpisał odwiedzający, plus `'`, to dodatkowy SQL w tym napisie zmienia filtr.
Zapytanie poniżej to to samo polecenie, gdy ktoś wpisze nazwisko, które nie zamyka cudzysłowu, i doda `OR 1 = 1`. `1 = 1` jest zawsze prawdziwe, więc WHERE już nie ogranicza wierszy. Ten sam rodzaj błędu przy UPDATE lub DELETE bez ciasnego WHERE może zmienić lub usunąć każdy wiersz.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' OR 1 = 1 ORDER BY customer_id;
Wynik: Wszyscy ośmioro klientów. Filtr nazwiska już nie ogranicza wyniku.
Poprawka: związane parametry
Nie sklejaj tekstu użytkownika z SQL. Wyślij polecenie z placeholderem i przekaż wartość osobno. PostgreSQL używa `$1`, `$2` itd. Baza traktuje wartość jako dane, nigdy jako składnię, więc nazwisko, które wygląda jak SQL, zostaje nazwiskiem.
Zapytanie, które piszesz, jest wtedy zawsze `WHERE last_name = $1`. Biblioteki i ORM-y nazywają to zapytaniem sparametryzowanym albo prepared statement. I tak musisz z tego korzystać: ORM, który skleja napisy, ma ten sam błąd.
SELECT first_name, last_name FROM customers WHERE last_name = 'Lopez' ORDER BY customer_id;
Wynik: Znowu Ana Lopez: wyszukiwanie ze związaną wartością, pokazane tu jako literał, bo ten edytor nie ma warstwy aplikacji.
Częste pytania
- Czy wystarczy owinąć wartość dodatkowymi apostrofami?
- Nie. Ludzie zapominają o escape, kodowania się różnią, a liczb w ogóle nie cytuje. Związane parametry omijają całą tę klasę pomyłek.
- Czy ORM oznacza, że mogę to zignorować?
- Tylko jeśli każde zapytanie idzie przez API parametrów. Surowe napisy SQL w ORM to nadal sklejony SQL. Wybierz query builder albo `execute(sql, [value])`.
- A UPDATE i DELETE?
- Ta sama zasada: WHERE musi używać parametrów, nigdy sklejonego tekstu. Brakujący albo popsuty WHERE przy tych poleceniach zmienia całą tabelę za jednym razem.