Помощ - Търсене - Потребители - Събития
Пълна версия: Сигурност при филтриране на данни с php
GGbit.info > Hi-Tech > Web разработка > Полезни статии
The Shaman
.:Увод
Много често при web програмирането ( един израз, за които мога да отнеса критика ) има възможност за
въвеждане на информация от потребители и визуализиране на въведеното в даденият сайт (Примери са: форуми, web
пощи, web стай за разговори, книги за гости.... и т.н.). При това положение е необходим контрол над въведените данни
с цел предпазване от въвеждане на нежелан скриптов код. Тъй като тази статия е предназначена за малко по-
напреднали няма да се впускам в подробни обяснения за видовете проверки и самият JavaScript. Нека видим една
примерна проверка за въведена поредица от символи съответстващи на поредицата "script":
<?
$text = "<script>alert('PxL');</script>";
$text = preg_replace('/script/',"dscript", $text);
echo $text;
?>


Резултатът от този код ще е следният:
- script се замества с dscript
- Скрипта не е изпълнен
- Извежда "alert('PxL');"

На ред #3 намира и заменя script с dscript , след което код-а изглежда така:
<dscript>alert('PxL');</dscript>


Таговете <dscript> и </dscript> не се интерпретират и скрипт-а не се изпълнява.
До тук изглежда, че сме си свършили работата от страна на проверката за това дали е
въведен скриптов код. Въпросът е какви други начини има за използване на скрипт в един HTML документ?

.:Expressions
Както всички знаем продукта Inernet Explorer на фирмата Microsoft позволява някой допълнения към различните
стандарти с цел оптимизация. Например опцията за CSS наречена expression. Expression бяха предоставени за Internet
Explorer версии след 5 и в момента се подържат.Целта им е да се постигне повече динамичност в CSS документите с
помощта на JavaScript изрази като главната идея е позициониране на елементите според дадено условие. Нека дам
пример за CSS блок с expression:

// примерa e от http://webfx.eae.net/dhtml/cssexpr/cssexpr.html
#myDiv
{
border: 10px solid Red;
width: expression(ieBox ? "100px" : "80px");
}


В случая имаме условие за задаване на широчината на даден елемент. Проверката е дали ieBox константата
е true или false, при true се задава широчина 100px при false 80px. Проверка за това дали браузъра е в т.нар Quircks
Mode или в стандартен режим ( Обикновено самият браузър определя според различни данни в документа като DOCTYPE например ).

Тук обаче ако се върнем на проверката ни за наличие на скрипт ще забележим, че според нея в примерният
CSS код няма такъв, а всъщност Internet Explorer го интерпретира....Нека променим кода за $text в кода за
проверка и видим резултат:
<?
$text = "<div style='top: expression(document.write(\"PxL\"));'></div>";
$text = preg_replace('/script/',"dscript", $text);
echo $text;
?>


И резултата е:
- Скрипта е изпълнен

Друг пример, причисляващ защитният ни код към неефективните е възможността за използване на JavaScript в
полето за адрес:
<?
$text = "<img src='java script: alert(\"PxL\")'>";
$text = preg_replace('/script/',"dscript", $text);
echo $text;
?>


Резултат:
- Скрипта е изпълнен

Общо взето има доста варианти, чрез които можем да въведем скриптов код в даден HTML документ...Всички те
обаче се свеждат до това да се избегне съвпадение при проверката с въведеният нежелан код и могат да бъдат
избегнати като се доусъвършенства и допълва самата проверка. Какво става обаче ако съществува възможност
браузърът да "пренебрегва" даден символ и да се абстрахира присъствието му в даден низ като чете заобикалящите
символи?

.:Нулеви символи
В следващите редове ще представя невъзможността на Internet Explorer да се справя с нулеви символи.
Първо какво е нулев символ (null char) и за какво се използва?
- Нулевият символ е символ с пореден номер 0 в символната таблица. Предназначен е за определяне на край на символни низове.

При интерпретирането на даден HTML документ Internet Explorer пренебрегва нулеви символи и интерпретира само заобикалящите ги. Едно доказателство е следният php скрипт:
<?
$text = "PxL";
echo $text;?>



Тук браузъра интерпретира само символите, който не са нулеви и извежда "PxL". Дори Microsoft Notepad не показва коректен резултат.Ако обърнем внимание на php функцията "preg_replace()", която ползваме, за да филтрираме въведеният код и направим следният тест:
<?
$text = "<script>alert('PxL');</script>"; $text =
preg_replace('/script/',"dscript", $text); echo $
;?>



Ще забележим, че функцията не намира търсеното "script" във входният низ, тъй като взима под внимание и нулевите символи. Резултатът обаче при Internet

Explorer e:
- Скрипта е изпълнен

Проблемът не е само в MS IE и MS Notepad. Функциите "copy" и "paste" в Windows, предназначени за работа с Clipboard-а
също имат проблеми при наличие на нулев символ, считат го за край на символните данни и не предоставят данните намиращи се след него. Комбинацията ALT+0 също отказва да го генерира.... Вариант-а тук е шестнадесетичен редактор, но и тогава данните трябва да
бъдат "пренесени" в съответният формуляр за изпращане на текст...

Нека оптимизирам малко първоначалният ни скрипт за защита и му дам име:

s1.php
<?
$text = $_GET["q"];
$text = preg_replace('/script/',"dscript", $text);
echo $text;
$f = fopen("test.html","w");
fwrite($f, $text);
fclose($f);
?>


Ще добавя и друг скрипт с който да извикам s1.php и му задам стойност за q съдържаща нулеви символи.
s2.php
<?
$fname = "test.php";
$query = "<script>alert('PxL');</script>"; $fp =
("127.0.0.1", 80, $errno, $errstr, 30); $out =
"GET /$fname?q=$query HTTP/1.1rn"; $out .=
"Connection: Closernrn"; fwrite(

$fp, $out); while (

!feof($fp) )
{
echo fgets($fp, 128); }
fclose(
$fp);?>



Резултатът е следният:
- Предават се всички данни до първият нулев символ.

Опит #3: s1.php?q=t%00e%00s%00t
Резултатът:
- t\0e\0s\0t.
- Самият браузър не предава нулевите символи

Какви тогава остават вариантите и има ли опастност?

.:Web пощи
Един вариант за пренасяне на данните може да бъде те да бъдат представени под друга форма ( кодирани ).Но в при извеждане в съответната web страница на данни в много редки случай имаме проверка дали са изпратени кодирани данни и съответно да бъдат декодирани. Казвам "в много редки случай" , защото в повечето web системи за електронна поща има възможност за автоматично декодиране на данни. Нека вземем например следното писмо:
> ----------------------------test.eml-----------------------------
> Date: Thu, 14 Jul 2005 04:42:16 GMT
> To: victum@somemail.com
> Subject: Null char IE bug
> MIME-Version: 1.0
> From: PxL
> Content-type: text/html; charset=windows-1251

> Content-Transfer-Encoding: base64
>
> ADwAcwBjAHIAaQBwAHQ+ZG9jdW1lbnQuYm9keS5kaXI9J3J0bCc7ADwALwBzAGMAcgBpAHAAdD4=
> ----------------------------/test.eml-----------------------------


Ако декодирам съдържанието ще видя (Замествам нулевите символи с [0] ):
[0]<[0]s[0]c[0]r[0]i[0]p[0]t>document.body.dir='rtl';[0]<[0]/[0]s[0]c[0]r[0]i[0]p[0]>

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

.:UTF-7 encoding (RFC 2152)
Идеята на UTF-7 кодовата таблица е да се даде възможност за използване на специални символи от Unicode таблицата.Този тип кодировка се използва при 7 битов трансфер на данни, в другите случай обикновено се ползва UTF-8. Символите се
представят във модифициран base64 и се заграждат между + и -. Проблема е, че всеки един Unicode символ може да бъде заместен според съответният му в UTF-7 таблицата.В това число и символи като < и >. Например:
<head>
<meta http-equiv=Content-Type content="charset=utf-7">
</head>

<body>
+ADw-+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4-
alert("PxL");
+ADw-/+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4-
</body>


+ADw-+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4- съответства на <script>
+ADw-/+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4- съответства на </script>

Резултатът от този код:
- Скрипта alert('PxL') се изпълнява

Тук всякакви проверки за наличие на "script" дават отрицателен резултат.
Използването на UTF-7 в MIME (RFC 2045) стандарта е следното:
Content-Type: text/plain; charset=UTF-7
Задава за тип кодова таблица на данните UTF-7 стандарта.
Отново проблема е при web пощите, тъй като при тях кодировката често се определя от тази, задедена от SMTP заявката. Ако вземем например следното електронно писмо:
> ----------------------------test.eml-----------------------------
> Date: Thu, 14 Jul 2005 04:42:16 GMT
> From: PxL
> MIME-Version: 1.0
> To: victum@somemail.com
> Subject: UTF-7 encoded mail
> Content-Type: text/plain; charset=UTF-7
> Content-Transfer-Encoding: quoted-printable
>
> <body>
> +ADw-+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4-
> alert("PxL");
> +ADw-/+AHM-+AGM-+AHI-+AGk-+AHA-+AHQ-+AD4-
> </body>
> ----------------------------/test.eml----------------------------


.:BB тагове
Начините за защита може да са много и различни, но от казаното до тук става ясно, че филтрирането трябва да е строго и да не позволява таговите символи < и >. Доста често напоследък обаче се наблюдава използването на т. нар.
BB тагове ( BB tags ). Представляват квадратни скоби [ и ]. Идеята е потребителят все пак да има начин да форматира и "украси" текст-а. Тук обаче се появява друг проблем. Поцедурата за прочитане на подобни тагове и преобразуването им в HTML тагове. Отново нека видим как ще изглежда един примерен скрипт за преобразуване:
<?
$text = "abv.bg";
$text = preg_replace("/(.*)/i","<a href=\"\1\">\2</a>", $text);
echo $text;
?>


Резултат:
- <a href="http://abv.bg">abv.bg</a>
- BB таговете [url] и [/url] се заместват със съответните HTML тагове <a> и </a>
- Текста в [url] след знака за равенство се помества в href и се слага в кавички
- Текста между [a] и [/a] се изписва между <a> и </а>

Но и тук не липсват проблеми...Един проблем може да се яви това, ако потребителят форматира първият текст, така, че да затвори кавичката на href . Ето пример за това:
<?
$text = "[url=http://abv.bg\" style=\"background: url('java script: alert(%27PxL%27);');]abv.bg[/url]";
$text = preg_replace("/(.*)/i","<a href=\"\1\" target=\"_blank\">\2</a>", $text);
echo $text;
?>


Резултат:
- <a href="http://abv.bg" style="background: url('java script: alert(%27PxL%27);');">abv.bg</a>
- Затваря се кавичката в href
- Изпълнява се скриптовият код в style

Горният пример практически е трудно приложим, тъй като доста от сървърите имат автоматична настройка за предпазване, а и за доста разработчици методът е известен и могат да го защитят само с една допълнителна проверка на addslashes() :
<?
$text = "[url=http://abv.bg\" style=\"background: url('java script: alert(%27PxL%27);');]abv.bg[/url]";
$text= addslashes ($text);
$text = preg_replace("/(.*)/i","<a href=\"\1\" target=\"_blank\">\2</a>", $text);
echo $text;
?>


Да, но и тук не отсъства опастност от XSS. Например в следният код addslashes() не е ефективна проверка:
<?
$text = "[url=java script:window.opener.document.write(%27PxL%27);window.close();]abv.bg[/url]";
$text= addslashes ($text);
$text = preg_replace("/(.*)/i","<a href=\"\1\" target=\"_blank\">\2</a>", $text);
echo $text;
?>


Резултат:
- При активиране на връзката се отваря нов прозоец
- Отвореният прозорец изпълнява скрипт и пише в отварящият window.opener
- Отвореният прозорец се затваря

.:Заключение
Защитите могат да бъдат много, но начините за "заобикалянето" им могат да са повече. Идеите за улеснение на потребителя трябва да бъдат добре обмислени, за да се избегнат всякакви нежелани действия. Не забравяйте, че дори след като филтрирате данните, въведени от потребителя е възможно защитният код да се "прескочи". Колко повече възможности за свободно форматиране на код-а има един потребител, толкова повече са възможностите за грешка при проверка. Използване на функции в php като htmlspecialchars(), strip_tags(), addslashes(), is_numeric() и т.н.

Бъдете параноични!


Автор: PxL
E-mail: PxL@hackbg.com
WEB: www.navbg.com
Източник: www.google.com ( ввв.гоогле.цом )
Идея: WWW ( World Wide Webmasters )
Relevant Advertise!
vIkToRsHeFa
Наистина изчерпателна статия във стил PxL наистина е на ниво както винаги. Помня преди време sourceland.hit.bg имаше адски много информация относно тази специялност - кодировките...

А за протокола... точно подобна дупка беше последният бъг във инвижън форумите версия 2.1.5 със който потребител изпратил код от този вид изпраща кукитата на външен потребител и когато не си си излязал от сесията може да се логне със твоятник само като замени стойностите. Естествено без достъп във админ панела защото за там се изисква задължително парола при новите инвижъни а и сесията се предава с линкове като по този начин трудно може да се засече каквото и да било. Същите бъгове ги имаше и за phpbb ако не ме лъже паметта.
Това е "lo-fi" версия на нашия форум. За да видите пълната версия, моля натиснете тук.
Invision Power Board © 2001-2018 Invision Power Services, Inc.