Oczywiście że można. I zapewnia to bezpieczeństwo przed atakami SQL Injection.
Pozwolę sobie zacytować fragment artykułu z wortalu, do którego wyżej linkowałem:
SQL injection ("wstrzykiwanie" komend SQL) to rodzaj zagrożenia, które może powstać w sytuacji, gdy za pomocą skryptu PHP pobierane są informacje z bazy danych a szczegółowe informacje dotyczące tego, jakie dokładnie dane skrypt powinien pobrać pochodzą z zewnątrz. Jest to spotykane zarówno w systemach zarządzania treścią jak i w znacznie prostszych skryptach. Dopóki zapytanie SQL budowane jest w oparciu o informacje przekazane do skryptu "z zewnątrz" skrypt może być narażony na atak typu SQL injection.
Załóżmy, że mamy skrypt, którego zadaniem jest wyświetlanie odpowiednich stron zależnie od wyboru użytkownika, który przekazywany jest do skryptu za pomocą zmiennej "page=" umieszczonej w adresie URL.
index.php?page=links
Następnie skrypt, korzysta z informacji przekazanej w zmiennej "page" i umieszcza je w zapytaniu SQL w celu pobrania z bazy i wyświetlenia odpowiedniej treści.
PHP:
<?php
$page= $_GET['page'];
$res= mysql_query("SELECT FROM table_with_pages WHERE page_id='{$page}' LIMIT 1");
?>
Powyższy przykład to bardzo popularny sposób pobierania danych z bazy, jednocześnie bardzo podatny na ataki. Atakujący musi jedynie ominąć pojedyncze znaki cudzysłowu i dodać odpowiednio spreparowany kawałek kodu:
index.php?page=%27%3B%20DROP%20DATABASE%20--
Jest to poprawne zapytanie URL, więc serwer zamieni zakodowane znaki na ciąg: '; DROP DATABASE. Spowoduje to zamknięcie rozpoczętego wcześniej cudzysłowu, wstawienie znaku kończącego zapytanie SQL (

, dodanie polecenia SQL powodującego usunięcie całej bazy danych i na koniec wstawienie znaku komentarza SQL (--) w celu usunięcia pozostałego z pierwotnego zapytania fragmentu polecenia SQL. W ten sposób możemy pożegnać się z naszą bazą danych.
Przytoczony przykład doskonale obrazuje zagrożenie. Należy pamiętać, że nie zawsze musi zadziałać dokładnie tak samo, szczególnie w przypadku gdy uprawnienia dostępu do bazy danych zostaną odpowiednio ustawione. Taki skrypt może jednak posłużyć do pozyskania lub umieszczenia przeróżnych informacji w naszej bazie danych - pobrania haseł użytkowników, zmiany hasła dla określonego użytkownika. Można również za jego pomocą zmodyfikować warunki wyszukiwania SQL za pomocą prostej reguły 'OR WHERE 1=1', przykładowo, pomijając w ten sposób sprawdzanie uprawnień dostępu lub jakikolwiek inne reguły wyszukiwania zamieszczone w zapytaniu SQL. Jest to możliwe, ponieważ dane przekazywane przez URL często są przekazywane do zapytania SQL właśnie jako warunki wyszukiwania.
Oczywiście, atakujący najprawdopodobniej nie pozna struktury bazy danych bez zobaczenia naszego kodu. Przy odpowiedniej ilość prób i odrobinie szczęścia może jednak uzyskać pewne informacje na temat budowy bazy danych, szczególnie w sytuacji gdy skrypt wyświetla na ekranie komunikaty o błędach (tym zagrożeniem dla bezpieczeństwa skryptu zajmiemy się później). Ale co z projektami open-source, których kod źródłowy jest dostępny dla wszystkich? Padają one bardzo często celem ataków, bo przy ogromnej ilości kodu nad którą pracuje bardzo dużo osób nie sposób wyłapać wszystkich błędów w skrypcie.
Najprostszym sposobem zabezpieczenia przed atakiem typu SQL injection jest usunięcie specjalnego znaczenia niektórych znaków, takich jak pojedynczy czy podwójny cudzysłów. Najlepiej w tym celu użyć funkcji natywnych dla bazy danych na której pracujemy. W naszym przypadku (baza MySQL) wygląda to następująco:
PHP:
<?php
$page= mysql_real_escape_string ($_GET['page']);
$res= mysql_query("SELECT FROM table_with_pages WHERE page_id='{$page}' LIMIT 1");
?>
Znacznie lepszym rozwiązaniem jest używanie identyfikatorów numerycznych gdziekolwiek to możliwe, zamiast "index.php?page=links" używając "index.php?page=1" i jednocześnie zmieniać typ danych przechowywanych w tej zmiennej na typ liczbowy:
PHP:
<?php
$page= (int) $_GET['page'];
$res= mysql_query("SELECT FROM table_with_pages WHERE page_id={$page} LIMIT 1");
?>
Kolejnym sposobem jest filtrowanie danych przechowywanych w zmiennych. Dla prostych identyfikatorów przeważnie wystarczą znaki alfanumeryczne (a-z0-9), w zupełności wystarczające w naszym przypadku.
Filtrowanie za pomocą wyrażenia regularnego i funkcji preg_match:
PHP:
<?php
$matches= array();
preg_match ('/^([a-z0-9])$/i', $page, $matches);
//Find page identifier in $matches[1]
?>
Oczywiście, jeżeli to tylko możliwe, nie ujawniaj kodu swoich skryptów.
Podsumowując, przydatne sposoby zabezpieczenia przed atakami typu SQL injection to:
* używanie oznaczeń numerycznych jako identyfikatorów kiedy tylko jest to możliwe,
* usuwanie specjalnego znaczenia niektórych znaków,
* filtrowanie danych pod kątem dozwolonych znaków,
* nie ujawnianie własnego kodu.
Na koniec, należy pamiętać, że takie same zagrożenia dotyczą danych przekazywanych do skryptów za pomocą zapytania typu POST. Jako że nagłówki zapytania HTTP to nic innego jak zwykły tekst, atakujący może bardzo łatwo napisać odpowiedni program (przykładowo, w języku C), którego zadaniem będzie połączenie się z naszym skryptem i wysłanie spreparowanego zapytania metodą POST.