SQL injection - bezpieczeństwo

Chciałbym się zapytać o bezpieczeństwo w aplikacjach internetowych np w PHP. Jak zabezpieczyć się przed SQL injection? Niektórzy twierdzą, że same addslashes() w pełni zabezpiecza przed atakami. Pomijam inne ataki XSS injection itp.

Edycja: Dzięki wszystkim za odpowiedzi :)

2 lata temu | edytowane przez: Manveru 4224121

  • Użycie ORMa lub PDO z parametrami powinno na sam początek wystarczyć. Na pewno nie wstawiaj danych od użytkownika bezpośrednio do zapytania SQL, możesz te dane najpierw odfiltrować przy pomocy np. wyrażeń regularnych.

  • Przede wszystkim filtrowanie danych wejściowych i stosowanie mysql_real_escape_string. Również wspomniane przez @kilas88 mechanizmy prekompilowanych zapytań z podstawianymi zmiennymi

    1. prepared statements (predefiniowane zapytania, MySQL, MS-SQL, PostgreSQL) więcej informacji
    2. bind variables (zmienne bindowane, Oracle) więcej informacji
    3. stored procedures czyli funkcje definiowane wewnątrz bazy SQL

    Te zabezpieczenia pozwalają na dokładną deklarację typu zmiennej podawanej do zapytania. Dodatkowo prepared statements daje znacznie większą wydajność wykonywania zapytań w większości systemów bazodanowych.

    W ograniczonym stopniu można stosować również settype() do podstawiania zmiennych do SQL'a czyli coś takiego:

    settype($offset, 'integer'); 
    $query = "SELECT id, nazwa FROM produkty ORDER BY nazwa LIMIT 10 OFFSET $offset;";
    

    Dodatkowym zabezpieczeniem może być mod_rewrite poprzez ukrycie oryginalnego adresu URL i zastąpienie go innym, czyli zwykłe (zaczerpnięte gdzieś z internetu):

    RewriteEngine On
    RewriteBase /
    RewriteRule ^produkty,([0-9]+),([0-9]+)\.html$ produkty.php?kategoria=$1&produkt=$2 [L]
    

    Tak jak już ktoś napisał walidować dane wprowadzane przez użytkowników, aby nie można było wpisywać apostrofa i słów które są składnią języka SQL (select, delete itd).

    Można też użyć strip_tags - wycina wszystkie tagi html z tekstu.

    Takie rzeczy jak sprawdzanie siły hasła wprowadzonego przez użytkownika do waszego serwisu oraz nadawanie użytkownikom minimalnych praw w korzystaniu z serwisu i kilka innych dobrych praktyk na pewno zniweluje podatność na ataki SQL Injection. Warto też być na bieżąco z nowymi atakami typu SQL Injection i szybko wprowadzać modyfikacje do swoich serwisów.

  • Przed SQL ijnection można zabezpieczyć się na kilka sposobów. Przede wszystkim jeżeli istnieje taka możliwość to warto zacząć od poziomu bazy danych nadając odpowiednie uprawnienia danym użytkownikom/tabelom itp. Niektóe z kont hostingowych oferują możliwość tworzenia użytkowników z prawami zapisu i odczytu jak również tylko odczytu. Nie trzeba chyba wyjaśniać, że taki użytkownik z prawami odczytu bardzo wiele dobrego wnosi do całej aplikacji. Jeżeli nasza aplikacja tylko POBIERA dane to jest to jakieś rozwiązanie.

    Jeżeli chodzi o bezpieczeństwo od strony PHP to popieram przedmówcę, addlaslashes() powinno załatwić problem. Warto też zwrócić uwagę na filtrację danych. Jeżeli w bazie musi znajdowąć się liczba, to warto też przefiltorwać dane pod tym kątem i na poziomie aplikacji nie pozwolić na próbę dodania np litery w miejsce liczby - wyrzuci błąd. Stąd warto zagłębić się w funkcje isint() isnumeric() itp. Kiedyś czytając książkę była przedstawiona fajna idea, która mówiła o tym, żeby tworząc aplikację zacząć od praw zerowych i nadawać je tak jakby "od tyłu"... Po prostu zakładamy, że każdy użytkownik nie może robić NIC, po czym staramy mu się udostępniać pewne funkcjonalności.

    EDIT: Niektórzy piszą tutaj o mysqlescapestring(). Z tego co się orientuję w PHP6 funkcja ta zniknie.

  • Kurs uw-team bardzo dobrze opisane zabezpieczanie strony.

  • addslashes wystarczy. Jeżeli ktoś twierdzi inaczej to niech da przykład jak można zrobić atak jeżeli jest addslashes.

  • Prawda jest taka, że do większości projektów wystarczy addslashes(). Można próbować innych metod, ale najważniejsza zasada, aby nie paść ofiarą SQL injection - filtrujcie dane wprowadzane przez uzytkowników. To wystarczy, na prawdę.

  • Proponuję poczytać tutaj: http://forum.php.pl/index.php?showtopic=23258 bardzo dużo ciekawych wpisów dających wiele do myślenia (WARTO PRZECZYTAC CAŁOŚĆ - mimo, że mało tego nie jest) oraz oficjalna strona php.net mówi troszeczkę o sql injection: http://php.net/manual/en/security.database.sql-injection.php

  • Znalazłem bardzo ciekawy kod, może komuś się przyda. Kod oczywiście jest rozwiązaniem na dziury typu SQL Injection.

    <?php
    $arrArguments = array();
    $intArgumentIndex = 0;
    
    function parseArgument($arrMatches) {
        global $arrArguments, $intArgumentIndex;
        $strMatch = $arrMatches[0];
        $strArgument = @$arrArguments[$intArgumentIndex++];
        switch ($strMatch) {
            case '%d': return (int)$strArgument;
            case '%s': return '"'.
              mysql_real_escape_string($strArgument).'"';
            case '%b': return (int)((bool)$strArgument);
        }    
    }
    
    function SQL($strSql) {
        global $arrArguments, $intArgumentIndex;
        $arrArgs = func_get_args();
        array_shift($arrArgs);
        $arrArguments = $arrArgs;
        $intArgumentIndex = 0;
        return preg_replace_callback('/(%[dsb])/', 'parseArgument',
          $strSql);    
    }
    ?>
    

  • Jakiś czas temu znalazłem stronę która pomaga w sprawdzeniu czy nasza aplikacja internetowa (nie ważne w jakim języku) jest podatna na ataki typu SQL injection: SQL Injection Cheat Sheet warto posprawdzać formularze ;)

    Generalnie trzeba pilnować żeby wszystko co ma być liczbą - było liczbą, na dane typu String nakładać wyrażenia regularne i nie ufać żadnym danym z POST i GET (nawet jeśli nie pochodzą z formularzy - istnieje przecież możliwość wysyłania żądań pomijając okno przeglądarki np. telnetem).

    W środowisku produkcyjnym warto też wyłączyć komunikaty błędów (error_reporting(0) w PHP) żeby nie podpowiadać hakerom czy ich żądania odnoszą skutek.

  • Polecam do walidacji wszelkie funkcje is*: http://pl2.php.net/manual-lookup.php?pattern=is

    Przede wszystkim isstring, isint, isnumeric. Przy używaniu tychże funkcji polecam pamiętać, iż dane pobierane GETem albo POSTem są typu string. Nawet jak pobieramy liczbę, to isint() zwróci FALSE. Kolejną ważną funkcją będzie addslashes() oraz unslashes(). Dlaczego unslashes() ? Ano dlatego, że domyślnie dane pobierane przez get i post w PHP 5 są opatrywane domyślnie znakami ucieczki. Piszę o tym dlatego, iż często w serwisach (nawet takich jak wp.pl) możemy zauważyć "\'" w treści. To właśnie świadczy o niedopatrzeniach, które mogą działać też w drugą stronę - zamiast zdublować znaki ucieczki (to jeszcze pół biedy) możemy o nich zapomnieć. Ktoś powie... niby nic. Ale pamiętajmy, że wiele wielkich serwisów ulegało atakom i były nimi takie wielkie witryny jak np allegro.

Zaloguj się, aby dodać swoją odpowiedź