2009-05-05 10 views
7

Jestem lekko doświadczonym programistą php i od 2007 r. Robię "to cholerstwo"; jednak nadal jestem stosunkowo n00bish, jeśli chodzi o zabezpieczanie moich aplikacji. W sposób, w jaki nie wiem wszystkiego, co wiem, mogłem i powinnam.Baza danych PHP/SQL wyszukująca dobre praktyki i bezpieczeństwo

Podniosłem Securing PHP Web Applications i czytam na ten temat, sprawdzając wszystko po drodze. Mam kilka pytań dotyczących ogólnej grupy SO, która odnosi się do kwerend bazy danych (głównie pod mysql):

Podczas tworzenia aplikacji, które umieszczają dane w bazie danych, to czy mysql_real_escape_string i ogólne sprawdzanie (is_numeric itp.) Na danych wejściowych jest wystarczające? A co z innymi typami ataków różniącymi się od wtrysku sql.

Czy ktoś mógłby wyjaśnić procedur przechowywanych i przygotowanych oświadczeń z nieco więcej informacji niż - robisz je i wykonywanie połączeń do nich. Chciałbym wiedzieć, jak działają, jakie walidacje toczą się za kulisami.

Pracuję w środowisku związanym php4, a php5 nie wchodzi w grę. Czy ktoś jeszcze był na tym stanowisku, co zrobiłeś, aby zabezpieczyć swoje aplikacje, podczas gdy wszystkie fajne dzieci używają tego słodkiego nowego interfejsu mysqli?

Co to są niektóre ogólne dobre praktyki, które ludzie uznali za korzystne, nacisk na stworzenie infrastruktury zdolnej do wytrzymania aktualizacji i możliwych migracji (takich jak przenoszenie php4 do php5).

Uwaga: po wyszukiwaniu nie można znaleźć niczego podobnego do tego, które trafiło w zabezpieczenia php-mysql.

+0

Haha dziękuje Jonowi – Louis

Odpowiedz

6

Moje zalecenia:

  1. rów mysqli na rzecz PDO (z kierowcą MySQL)
  2. użycie PDO paremeterized przygotowanych sprawozdań

Następnie można zrobić coś takiego:

$pdo_obj = new PDO('mysql:server=localhost; dbname=mydatabase', 
        $dbusername, $dbpassword); 

$sql = 'SELECT column FROM table WHERE condition=:condition'; 
$params = array(':condition' => 1); 

$statement = $pdo_obj->prepare($sql, 
    array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
$statement->execute($params); 
$result = $statement->fetchAll(PDO::FETCH_ASSOC); 

Plusy:

  1. Nie więcej instrukcja ucieczki od PDO robi to wszystko dla Ciebie!
  2. W stosunkowo łatwy sposób można szybko przełączyć bazy danych.

Wady:

  • nie mogę myśleć o żadnych.
+0

+1 Podoba mi się ten pomysł – Louis

3

Zwykle nie działa w PHP, więc nie mogę udzielać porad przeznaczonych specjalnie do Twoich potrzeb, ale proponuję, aby spojrzeć na stronie OWASP, szczególnie top 10 luk zgłosić: http://www.owasp.org/index.php/Top_10_2007

Na tej stronie dla każdej luki pojawi się lista rzeczy, które możesz zrobić, aby uniknąć problemu na różnych platformach (.Net, Java, PHP, itp.).

Odnośnie przygotowanych wyciągów, pracują, udostępniając bazę danych silnik wie, ile parametrów i jakich typów można się spodziewać podczas konkretnego zapytania, wykorzystując te informacje, silnik może zrozumieć, które znaki są częścią rzeczywistego parametru, a nie coś, co powinno być parsowane jako SQL jak "(apostrof) jako część danych zamiast" jako ogranicznik łańcuchów znaków ". Niestety nie mogę podać więcej informacji skierowanych na PHP, ale mam nadzieję, że to pomoże.

+0

Dzięki temu i temu wyjaśnieniu, chociaż znałem je wszystkie w poszczególnych częściach, które doprowadziły do ​​tego, dlaczego wszyscy razem. "ma sens" – Louis

9

Odpowiedź Javiera, która ma link Owasp, to dobry początek.

Istnieje jeszcze kilka rzeczy, które można zrobić więcej:

  1. Odnośnie ataków SQL injection, można napisać funkcję, która usunie wspólne SQL z wejścia typu „drop” lub „DELETE * GDZIE ", tak:

    * $ sqlarray = array (" DROP "," lub 1 = 1 "," wybór związków "," SELECT * FROM "," wybierz hosta "," utwórz tabelę "," OD użytkowników "," users WHERE "); *

    Następnie zapisz funkcję, która sprawdzi dane wejściowe przed tą tablicą. Upewnij się, że dowolne elementy wewnątrz $ sqlarray nie będą typowymi danymi wejściowymi użytkowników. (Nie zapomnij o użyciu strtolower, dzięki Lou).

  2. Nie jestem pewien, czy memcache działa z PHP 4, ale można wprowadzić ochronę przed spamem z pamięcią memcache, dopuszczając tylko określony zdalny dostęp IP do strony process.php X razy w Y okresie czasu.

  3. Przywileje są ważne. Jeśli potrzebujesz tylko uprawnień do wstawiania (np. Przetwarzanie zamówień), powinieneś zalogować się do bazy danych na stronie procesu zamawiania z użytkownikiem, który ma tylko uprawnienia do wstawiania i może wybierania. Oznacza to, że nawet jeśli doszło do wstrzyknięcia SQL, mogli oni jedynie wykonywać zapytania INSERT/SELECT, a nie usuwać lub restrukturyzować.

  4. Umieść ważne pliki przetwarzania php w katalogu takim jak/include. Następnie odrzuć wszystkie adresy IP dostępu do katalogu/include.

  5. Połóż solone MD5 z agentem użytkownika + pilotem + solą w sesji użytkownika i sprawdź, czy na każdym załadowaniu strony znajduje się poprawny plik MD5 w pliku cookie.

  6. Nie zezwalaj na niektóre nagłówki (http://www.owasp.org/index.php/Testing_for_HTTP_Methods_and_XST). Nie zezwalaj PUT (jeśli nie potrzebujesz wysyłania plików)/TRACE/CONNECT/DELETE headers.

+1

Dobre pomysły, gdybym mógł edytować twój wpis, chciałbym zwrócić uwagę na strtolower na dopasowaniu do sqlarray. I tak memcache działa z php4 – Louis

0

Stosuj procedury przechowywane dla każdej czynności związanej z wkręcaniem do bazy danych i użyj parametrów wiązania dla wszystkich zaznaczeń.

1

Mogę się mylić, ale czy nie powinno wystarczyć użycie mysql_real_escape_string danych podanych przez użytkownika?

chyba gdy są numery, w takim przypadku należy upewnić się, że są w rzeczywistości zamiast numerów za pomocą na przykład ctype_digit lub is_numeric lub sprintf (używając %d lub %u wymusić wejście do numeru).

Ponadto, mając serarate mysql użytkownika o skryptach PHP, który może tylko SELECT, INSERT, UPDATE i DELETE jest dobrym pomysłem ...


Przykład z php.net

Przykład # 3 Zapytanie "Najlepsza praktyka"

Użycie mysql_real_escape_string() wokół każdej zmiennej zapobiega iniekcji SQL. Ten przykład demonstruje metodę "najlepszej praktyki" do sprawdzania bazy danych, niezależnie od ustawienia Magic Quotes.

Zapytanie zostanie teraz wykonane poprawnie, a ataki SQL Injection nie będą działać.

<?php 
    if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) { 
     // Connect 

     $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password'); 

     if(!is_resource($link)) { 

      echo "Failed to connect to the server\n"; 
      // ... log the error properly 

     } else { 

      // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON. 

      if(get_magic_quotes_gpc()) { 
       $product_name  = stripslashes($_POST['product_name']); 
       $product_description = stripslashes($_POST['product_description']); 
      } else { 
       $product_name  = $_POST['product_name']; 
       $product_description = $_POST['product_description']; 
      } 

      // Make a safe query 
      $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)", 
         mysql_real_escape_string($product_name, $link), 
         mysql_real_escape_string($product_description, $link), 
         $_POST['user_id']); 

      mysql_query($query, $link); 

      if (mysql_affected_rows($link) > 0) { 
       echo "Product inserted\n"; 
      } 
     } 
    } else { 
     echo "Fill the form properly\n"; 
    } 
2

AFAIK, PHP/mySQL zwykle nie ma sparametryzowanych zapytań.

Używanie sprintf() z mysql_real_escape_string() powinno działać całkiem dobrze. Jeśli użyjesz odpowiednich ciągów formatów dla sprintf() (np. "% D" dla liczb całkowitych), powinieneś być całkiem bezpieczny.

+0

To już nie jest najlepsza odpowiedź, ponieważ wszystko poszło dalej. Odpowiedź Krisa wspomina o przygotowanych oświadczeniach PDO dla PHP, a przygotowane instrukcje są również obsługiwane przez najnowsze wersje MySQL. – beldaz

+0

Stało się to popularnym pytaniem, więc przeniosłem odpowiedź w nadziei na zmniejszenie rozprzestrzeniania dezinformacji. Wszystkie dobre odpowiedzi tutaj, Kris miał rację, patrząc na najlepszą praktykę. – Louis