Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zabezpieczanie danych wejściowych
Forum PHP.pl > Forum > Gotowe rozwiązania > Szukam
Confushi
Witam,

to mój pierwszy post więc proszę o wyrozumiałość. Nie jestem programistą ale czasem raz na miesiąc coś tam skrobnę, a obecnie realizuje pewien projekt gry dla siebie. Dlatego zrodził się pewien problem.

Zależy mi na czyszczeniu wszystkich informacji, które mogłyby spowodować obniżenie poziomu bezpieczeństwa. Trochę na ten temat czytałem i widziałem bardzo wiele rozwiązań, które czyściły POST i GET. Najczęściej polegały on na zastosowanie filtrów czyszczących znaki lub je zamieniające. Ostatecznie znalazłem pewne rozwiązanie na algorytmy.pl gdzie za pomocą parametru określam w jaki sposób czyszczę. Niestety jednak czuję niedosyt. Na pewno to nie zabezpiecza przed atakami SQL Injection i innymi (mi nie znanymi problemami), do baz danych używach PDO.

I teraz pytanie do was, czy znajdę gdzieś gotowe rozwiązanie, które pozwala w sposób kompleksowy podejść do zabezpieczania, poprzez kompleksowe to takie, że wywołujemy na początku klasę i ona sobie wszystko robi co uzna za konieczne. Nie mam w tym doświadczenia, dlatego chciałbym poznać waszą opinie jak można sobie z tym problemem najlepiej poradzić (mogę wkleić fragment tego co już mam).
gothye
PDO i bindowanie danych ,szukaj w google
Crozin
Nie istnieje coś takiego jak "odpalę sobie klasę i ona przefiltruje wszystko co uzna za konieczne", bo to jak dane będą filtrowane zależeć będzie od tego, gdzie będą one wykorzystywane. Inaczej potraktować trzeba dane, które będą miały być wrzucone do zapytania SQL (PDOStatement::bindValue()), inaczej dane wyświetlane w HTML-u (htmlspecialchars), inaczej dane przekazywane do JS (transport JSON-em: json_encode), inaczej trzeba filtrować dane pod XML, CSV, INI, nagłówki HTTP/MAIL i całą masę innych rzeczy. Skąd taka klasa miałaby wiedzieć jak zająć się otrzymanymi danymi?
Confushi
Dziękuje za pierwsze odpowiedzi (w szczególności PDOStatement::bindValue()), co do tego, że klasa nie mogła by powstać to nie przesadzajmy, wystarczyłoby nadać odpowiedni atrybut po którym klasa by wiedziała co zrobić ze zmienną/tablicą. Bardziej nielogiczne wydaje mi się budowanie czegoś takiego od zera, przecież do klasy można dopisać sobie nowe funkcje, a standardowe filtrowania można by zamknąć w kilkunastu gotowych.

Na co (jako amator) powinienem przede wszystkim zwrócić uwagę? Może macie jakiś link do artykułu, który to omawia (szukałem jakiś czas w Google, ale nie znalazłem niczego czego nie wiedziałem).
Crozin
Filtrowanie musi odbyć się w ściśle określonym momencie, najczęściej tuż przed faktycznym użyciem potencjalnie niepoprawnych/niebezpiecznych danych w danym środowisku. Samym filtrowaniem powinny zajmować się obiekty/funkcje operujące na "źródle danych" i tak w przypadku bazy danych jest to PDOStatement::bindValue(), w przypadku XML-a będzie to DOMDocument::saveXML (bo dopiero w tym momencie przykładowo znak "<" występujący w jakimś tekście musi zostać zamieniony na "<"), a przy wyświetlaniu danych pobranych z bazy danych w dokumencie HTML skorzystasz z htmlspecialchars:
  1. <h1>Profil: <?php echo htmlspecialchars($profile->getFullname()) ?></h1>
  2. <!-- tutaj polecam korzystać z jakiegoś systemu szablonów, bądź biblioteki pomocniczej, która uprościłaby nieco powyższy zapis. -->


Danych nie możesz sobie tak od przefiltrować w innym miejscu. Przykład:
  1. $tytuł = "Cukierki M&M's - nowy smak!";
Powiedzmy, że tą zmienną chcesz zapisać w bazie danych i jednocześnie wyświetlić na stronie w HTML-u. Nie możesz na początku potraktować jej htmlspecialchars() bo w bazie zapisze się "M&M's" co jest oczywiście bzdurne. Między innymi z tego powodu nie za bardzo da się stworzyć wygodną w użyciu "klasę do filtracji".
Cytat
Na co (jako amator) powinienem przede wszystkim zwrócić uwagę?
1. Postaraj się poczytać jak najwięcej o zabezpieczeniach i atakach na aplikacje webowe - nie znając zagrożeń ciężko się przed nimi bronić.
2. Zawsze testuj czy aplikacja zachowuje się poprawnie w przypadku otrzymania nieprawidłowych danych.
Confushi
Dzięki Crozin, super post. Ludzie często zapominają, że najważniejsze to czyszczenie zmiennych w odpowiednim momencie. Obecnie moja konstrukcja wygląda następująco:

  1. index.php
  2. <?php
  3.  
  4. //Czyszczenie zmiennych
  5. require_once("include/security/clear.php");
  6. clear_array($_POST, 1); //czyszczenie całej tablicy
  7. clear_array($_GET, 1); //czyszczenie całej tablicy
  8. clear_variable($_GET['article_id'], 3); //mapowanie na int-a


Potem mam funkcje, która czyści:

  1. Dla tablic
  2. if ($metoda==1) {
  3.  
  4. // usuwam ukośniki i zabezpieczam znaki specjalne po swojemu
  5. if (get_magic_quotes_gpc()) $tablica[$klucz] = stripslashes($wartosc);
  6. $tablica[$klucz] = str_replace(
  7. array('"' , '&' , '<' , '>' , "\0" , '\\' , "'"), // przed zmianą
  8. array( '&quot;' , '&amp;' , '&lt;' , '&gt;' ,'' , '\\\\' , "\'"), // po zmianie
  9. $wartosc
  10. );


  1. Dla zmiennych
  2. function clear_variable($variable, $metoda) {
  3. if ($metoda==3) {
  4.  
  5. // wszystkie zmienne mapuję na liczby całkowite
  6. $variable = (int)$variable;
  7.  
  8. }
  9. return $variable;
  10. }


Przyjąłem taką taktykę, że czyszczę ogólnikowo wszystko, a jeżeli potrzebuje dodatkowe odfiltrowywanie, to wywołuje funkcje z innym atrybutem. Mam nadzieje, że na początek, nie jest źle.
Crozin
Hmmm... napisałem cały post odnośnie tego dlaczego takie rozwiązanie jest złe, wręcz fatalne, poprałem to prostym przykładem, po czym zaprezentowałeś jako "mam nadzieję, nie jest źle" dokładnie to o czym pisałem, że jest złe. Trochę pogubiłem się.

Jeszcze jeden przykład demonstrujący dlaczego to rozwiązanie jest beznadziejne:
  1. <?php
  2.  
  3. /* Prosta wyszukiwarka firm po nazwie: przykładowe dane z bazy danych:
  4.  
  5. +----------+-----------------------+
  6. | company | address |
  7. +----------+-----------------------+
  8. | Adidas | ... |
  9. | H&M | ... |
  10. | Nike | McDonald's Street 123 |
  11. | Joe's CO | ... |
  12. +----------+-----------------------+
  13. */
  14.  
  15. // Teraz dla przykładu w pętli obrazującej 3 osobne wyszukiwania firm: Nike, H&M, Joe's CO.
  16.  
  17. foreach (array("Nike", "H&M", "Joe's CO") as $name) {
  18. // normalnie zmienna $name pochodziła by z $_GET['search'];
  19.  
  20. $name = clear_variable($name, 1); // wartość zmiennej to odpowiednio: Nike, H& amp ;M, Joe\'s CO
  21.  
  22. echo 'Wyniki wyszukiwania dla frazy: ' . $name; // Odpowiednio: Nike (OK), H&M (& jako encja, ale OK), Joe\'s CO (NIE OK)
  23.  
  24. $stmt = $pdo->prepare('SELECT ... FROM companies WHERE name = :name');
  25. $stmt->execute(array('name' => $name));
  26.  
  27. $company = $stmt->fetch();
  28.  
  29. $company = clear_array($company, 1);
  30.  
  31. echo $company['name'] . ': ' . $company['address'];
  32. }
Dla "Nike" wyszuka, ale adres wyświetli jako "McDonald\'s Street 123". Dla początkowej frazy "H&M" oraz "Joe's CO" nie znajdzie niczego bo faktycznie wyszukiwać będzie "H& amp ;M" oraz "Joe\'s CO".

Myślę, że teraz już widzisz ułomność tego rozwiązania.

PS. Za stosowanie jakiś magicznych numerków typu funkcja($zmienna, 3); powinno obcinać się palce.
PPS. & amp ; - oczywiście powinno być bez spacji, ale forum nie przepuszcza czegoś takiego.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.