Pytanie Czy powinniśmy zawsze wiązać nasze instrukcje SQL?


Badałem PDO bindValue(). Wiem, że przygotowanie moich instrukcji SQL z PDO powstrzymuje iniekcje SQL.

Przykład kodu:

$stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title');
$stmt->bindValue(':id', PDO::PARAM_INT);
$stmt->bindValue(':title', PDO::PARAM_STR);
$stmt->execute();

Wiążąc identyfikator jako numer, a tytuł jest łańcuchem, możemy ograniczyć szkody, które powstają, gdy ktoś próbuje wykonać iniekcję SQL wewnątrz kodu.

Czy zawsze powinniśmy wiązać nasze wartości z PDO::PARAM_ więc możemy ograniczyć to, co można wyciągnąć z bazy danych w iniekcji SQL? Czy to zwiększa bezpieczeństwo przy pomocy ChNP bindValue()?


14
2018-05-07 07:24


pochodzenie


Jeśli nie wiążisz parametrów używanych w a LIMIT jako int zapytanie nie będzie reagować tak, jak myślisz (nie pamiętam, czy się nie powiedzie, czy je zignoruje). - h2ooooooo
... w przeciwieństwie do czego? Inne metody wiązania, które nie są bindValue? Opuszczając naszą PDO::PARAM_ argument? Lub całkowicie rezygnując z prepare API? - deceze♦
Jestem dość pewny, co oznacza OP: "Czy muszę użyć PDO::PARAM_INT dla numeru lub czy mogę przetrwać z ustawieniem domyślnym PDO::PARAM_STR to jest wybrane, jeśli nie wybieram typu parametru? Rozumiem, że to dodaje 'Wokół liczb, ale czy to naprawdę ma znaczenie?". - h2ooooooo
@ H2ooooooo To jest zasadniczo pytanie, ale je sformułowałeś droga lepiej niż ja. Nie rozumiem, dlaczego chciałbyś, żeby int był żądłem. Może jestem zbyt logicznym myśleniem. - Traven
@Fluorocarbon Możesz czerpać korzyści z czytania mysql - cytować numery czy nie?. Powiedział, że zawsze używam własnego wrappera DB, który sprawdza typ PHP, a następnie wybiera poprawny typ PARAM. (stackoverflow.com/a/22235348/247893) - h2ooooooo


Odpowiedzi:


W jednym są dwa pytania. Istotne jest, aby ich nie mylić

  1. Powinniśmy zawsze używać a symbol zastępczy reprezentować zmienne dane w zapytaniu?
  2. Powinniśmy zawsze używać określonej funkcji w kod aplikacji przestrzegać powyższej zasady?
    Również z wyjaśnienia w komentarze pod postem otwierającym, trzecie pytanie można zobaczyć:
  3. Czy zawsze powinniśmy używać trzeciego parametru, czy też można zezwolić PDO na domyślne powiązanie wszystkich parametrów jako łańcuchów?

1. Na pierwsze pytanie odpowiedź jest absolutnie i zdecydowanie TAK.

Podczas gdy drugi, ze względu na kod bezpieczeństwa i DRYness -

2. Jeśli to możliwe, unikaj ręcznego wiązania.

Istnieje wiele sposobów uniknięcia ręcznego wiązania. Niektórzy z nich są:

  • ORM to doskonałe rozwiązanie dla prostych operacji CRUD i musi mieć nowoczesną aplikację. Ukryje całkowicie SQL przed tobą, wykonując powiązanie za kulisami:

    $user = User::model()->findByPk($id);
    
  • Konstruktor kwerend jest także drogą do przebycia, ukrywając SQL w niektórych operatorach PHP, ale ponownie ukrywając powiązanie za kulisami:

    $user = $db->select('*')->from('users')->where('id = ?', $id)->fetch();
    
  • pewna biblioteka abstrakcji może zająć się przekazanymi danymi za pomocą typ-napotkane zastępcze, ponownie ukrywając faktyczne powiązanie:

    $user = $db->getRow("SELECT * FROM users WHERE id =?i", $id);
    
  • jeśli nadal używasz PHP w ubiegłych stuleciach i posiadasz surowy PDO na całym kodzie - możesz przekazać swoje zmienne w execute (), wciąż oszczędzając sobie pisania:

    $stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?');
    $stmt->execute([$id]);
    $user = $stmt->fetch();
    

Z trzeciego pytania - tak długo, jak wiążą liczby jako łańcuchy znaków (ale nie przeciwnie!)

3. Z mysql wystarczy wysłać prawie każdy parametr w postaci ciągu

ponieważ mysql zawsze konwertuje twoje dane na właściwy typ. Jedyny znany mi przypadek to klauzula LIMIT, w której nie można sformatować liczby jako ciągu znaków - tak więc jedynym związanym przypadkiem jest jeden gdy PDO jest ustawiony w trybie emulacji i musisz przekazać parametr w klauzuli LIMIT. We wszystkich innych przypadkach możesz pominąć trzeci parametr, a także wyraźne wywołanie bindValue() bez problemu.


10
2018-05-07 07:40





Powinieneś zdecydowanie skorzystać z prepare API i przekazywać wartości oddzielnie od zapytania, w przeciwieństwie do zwykłej interpolacji ciągów (na przykład. "SELECT * FROM foo WHERE bar = '$baz'" → zły).

W przypadku parametrów wiązania dostępne są trzy opcje:

Nie ma znaczenia, z których z nich korzystasz, wszystkie są jednakowo bezpieczne. Zobacz te odpowiedzi, aby uzyskać szczegółowe informacje na temat różnic:

Podczas używania bindParam lub bindValue, mijając trzeci PDO::PARAM_ typ argumentu jest opcjonalny. Jeśli go nie przekażesz, domyślnie będzie wiązać argument jako ciąg. Oznacza to, że możesz skończyć z zapytaniem równoważnym ... WHERE foo = '42' zamiast ... WHERE foo = 42. Zależy od bazy danych, jak sobie z tym poradzi. MySQL automatycznie rzuci łańcuch na liczbę, tak jak to robi PHP (np '42' + 1). Inne bazy danych mogą być bardziej wybredne co do typów.

Ponownie wszystkie opcje są równie bezpieczne. Jeśli próbujesz powiązać ciąg znaków 'foo' za pomocą PDO::PARAM_INT, ciąg będzie rzutowany na liczbę całkowitą i odpowiednio związany jako wartość 0. Nie ma możliwości wstrzyknięcia.


10
2018-05-07 07:37





Tak, powinieneś zawsze wiązać paramy z przygotowanym oświadczeniem. Jest bezpieczniejszy i ogranicza iniekcję SQL. Ale nie jest to jedyny sposób, w jaki należy wykonać kwerendy: wymagana jest prawidłowa kontrola typu, najlepiej jeśli zamapujesz wiersz w obiekt i wyrzucisz w nim wyjątek, jeśli zawiera on nieprawidłowe dane.

Mam nadzieję, że będę przydatna!


2
2018-05-07 07:31





tak, wiązanie jest drogą do zrobienia. Lub sparametryzowane zapytania, które mają bardziej ogólny termin.

@Theo wykonuje wspaniałą pracę wyjaśniając, dlaczego sparametryzowane zapytania są drogą do zrobienia

Możesz również użyć procedury przechowywane dla dodatkowego bezpieczeństwa, ale jest to nadmierne zabicie, jeśli masz jedną aplikację do jednej bazy danych. Jest dobry dla wielu aplikacji w jednej bazie danych, aby zapewnić spójność podczas przetwarzania danych


1
2018-05-07 07:40



co to jest "dodatkowe" bezpieczeństwo i jak dostarczają go przechowywane w nim procedury? - Your Common Sense
@TwójCommonSense IDK, dlaczego głosowanie w dół, jak nic nie jest z moją odpowiedzią Tylko tyle, że może brakować niektórych informacji lub odrobinę vauge, o których wspomina sekcja komentarzy ... Dzięki dodatkowym zabezpieczeniom możesz wymusić przypisanie danych typu do Twoja baza danych poprzez sprawdzenie danych. Injection SQL nie jest jedynym problemem bezpieczeństwa w SQL ... - Krimson
Nie rozumiem słowa "dodatkowy" stosowanego do bezpieczeństwa. Jeśli twój kod jest bezpieczny - żadne "dodatki" nie są potrzebne. Jeśli nie, to te "dodatki" nie zagwarantują ci bezpieczeństwa. Widziałem zbyt mało ludzi, którzy rzeczywiście stosowali procedury przechowywane jako środek ochrony przed zastrzykami. Ale widziałem mnóstwo, którzy po prostu powiedzieć siebie nawzajem, aby z nich korzystać. - Your Common Sense
@YourCommonSense Jeśli masz wiele aplikacji wstawiających dane do jednej bazy danych. Jak kontrolujesz dane? Co się stanie, jeśli jedna aplikacja wstawi zniekształcone dane, które mogą spowodować, że inna aplikacja nie będzie działać poprawnie? Jeśli korzystasz z procedur zapisanych w bazie, masz scentralizowany sposób sprawdzania typu danych wprowadzanych / wstawianych, aby upewnić się, że nie jest on zdekompresowany - Krimson
Ponieważ bez niego twoja odpowiedź stanie się po prostu linkiem do innej odpowiedzi. W rzeczywistości jest to inne pytanie. - Your Common Sense