Styk baz danych z WWW to często miejsce, gdzie łatwo o poważną lukę bezpieczeństwa, tzw SQL Injection. Popatrzmy na prosty formularz HTML, pobierający od użytkownika nazwę przedmiotu. Otrzymana nazwa jest przekazywana do programu w PHP, który zadba o wydobycie z bazy danych średniej oceny z tego przedmiotu.
<form action="srednie.php" method="post"> Podaj nazwę przedmiotu: <input type="text" name="przedmiot"><br> <br> <input type=submit value="Szukaj"> </form> |
Prosty program srednie.php
mogłby wyglądać tak
<?php $przedmiot = $_POST["przedmiot"]; $link = pg_connect("host=lkdb dbname=usos user=scott password=tiger"); $wynik = pg_query($link, "SELECT AVG(ocena) AS srednia FROM Oceny WHERE przedmiot = '" . $przedmiot . "'"); $ile = pg_numrows($wynik); if ($ile == 0) { echo "<center><strong>Nie ma nic</strong></center>"; $imie = ""; } else { $oceny = pg_fetch_array($wynik, 0); $srednia = $oceny["srednia"]; } ?> <form action="zoo2.php" method="post"> <?php echo "Średnia: " . $srednia . "<br><br>"; echo "Podaj inny przedmiot: <input type=text name='przedmiot' value='$przedmiot'><br><br>"; pg_close($link); ?> <input type=submit value="Szukaj"> </form>
Ale ciekawski użytkownik mógłby wpisać taką wartość dla przedmiotu
Po sklejeniu napisów dostaniemy
SELECT AVG(ocena) AS srednia FROM Oceny WHERE przedmiot = 'Bazy danych' and indeks = '123456';
Bardzo przyzwoite zapytanie, tyle że narusza prywatność osoby o indeksie 123456, ponieważ wyświetli jej ocenę z tego przedmiotu.
Złośliwy użytkownik mógłby wpisać następującą wartość dla przedmiotu
Po sklejeniu napisów dostajemy
SELECT AVG(ocena) AS srednia FROM Oceny WHERE przedmiot = 'Bazy danych'; delete from Oceny where przedmiot ='IPP';
Ogólna zasada bezpieczeństwa mówi: ,,Nigdy nie ufaj danym otrzymanym od użytkownika. Sprawdzaj!''.
W PHP są dwa sposoby. Pierwszy to w każdym otrzymanym napisie
wszystkie znaki, które nie są literami ani cyframi, poprzedzić prefiksem
'\'
, odbierającym im specjalny character. Można to zrobić
samemu, ale lepiej użyć którejś funkcji bibliotecznej, na przykład
pg_escape_string()
. Są one dostosowane do konkretnych
systemów baz danych --- w tym przypadku do Postgresa
$wynik = pg_query($link, "SELECT AVG(ocena) AS srednia FROM Oceny WHERE przedmiot = '" . pg_escape_string($przedmiot) . "'");
Drugi sposób to zamiast pg_query
użyć funkcji
pg_query_params
. Ma ona dodatkowy argument: tablicę
wartości dla parametrów. W treści zapytania parametry representowane
są jako $1
, $2
, ...
$wynik = pg_query($link, "SELECT AVG(ocena) AS srednia FROM Oceny WHERE przedmiot = $1", array($przedmiot));
Na stronie laboratorium (u dołu) mamy dwa przykłady takiej interakcji z bazą danych. W pierwszym dla podanego gatunku odnajdujemy informacje o jakimś zwierzaku z tego gatunku.
Drugi przykład to wstawianie nowego gatunku do bazy danych. Pokazuje, także obsługę błędów.