* Валидиране на типовете данни при SQL

Публикувано на 30 ноември 2008 в раздел ПТСК.

Дотук разгледахме най-често срещаният проблем, позволяващ вмъкване на нежелан SQL код – лошо филтриране на входните данни. Отбелязахме, че е по-добре да даваме множество от позволени стойности на входните данни, а не просто да забраняваме непозволените символи. За да обясним защо ще демонстрираме чрез пример, в който няма да използваме кавички при изпълнение на заявката. Нека например изпращаме следната заявка:

	$sql = "SELECT * FROM stats WHERE id=$id"

В случая полето с име „id“ е от тип int и поради тази причина не е нужно ограждането на стойността в кавички. Ако подадем например числото „5″ ще се генерира следната заявка към базата от данни:

	SELECT * FROM stats WHERE id=5;

Ако обаче подадем „23 OR 1=1″ ще се получи:

	SELECT * FROM stats WHERE id=23 OR 1=1;

Тази заявка очевидно е винаги валидна и ще изкара всички данни от базата от данни. В нея не използвахме нито един непозволен символ. Възможностите за пробив са много, в зависимост от вида на заявката. При заявка от тип UPDATE или DELETE например може да се достигне до фатални за базата от данни резултати.

Как да се защитим? Отговорът е ясен – валидирайте не само подадените символи, но и самите типове данни:

	if(is_numeric($id){
		$sql = "SELECT * FROM stats WHERE id=$id"
		...
	}
	else{
		echo "Are you trying to do SQL injection?";
		exit();
	}

Възможно е и използване на вградените функции на сървъра за база от данни, но на практика е по-добре да валидирате в собственото приложение (а защо не и по двата начина?).

Друга широко използвана практика е използването на процедури на сървъра за базата от данни, вместо подаването на директни заявки. Тази практика не винаги може да гарантира коректно филтриране!

Отново ще припомним и едно друго, вече споменато основно правило за базите от данни – давайте толкова привилегии на потребителя, колкото са му нужни! Грешен подход е да имаме един потребител за базата от данни, който се използва за всички видове заявки.



2 коментара за “Валидиране на типовете данни при SQL”

 
  1. Мартин:

    Когато се очаква дадена променлива да е число, я минавам през (int). Примерно $id = (int)$_GET['id] и тя се превръща съответно в число. Това е малко по-бързо отколкото да се ползват готови функции от рода на intval() и is_nummeric. Ако пък се очаква да са някакви символи ги минавам през mysql_real_escape_string(). Евентуално, ако ще се добавя в базата данни някаква информация, е хубаво да се минава през функции за обезвреждане на html таговете от рода на strip_tags. Аз ползвам точно нея и ми изглежда сигурна.

     
  2. Филип Петров:

    О, не – това, което правиш не е добре. Пробвай например „echo (int)“1234abcd“;“. Резултатът е „1234″. Това няма да счупи SQL заявката, да. Но има един основен въпрос: „след като знаем, че дадена променлива е с невалидни данни, то защо въобще трябва да се изпълнява SQL заявка?“. И тук спорът приключва в полза на „is_numeric“ :)

     

Trackback URI | RSS за коментарите

Пусни коментар