Просмотр полной версии : Статья про анти sql-inj
Статья про защиту от SQL-inj
Что такое SQL-inj?
Сам знаешь. Иначе бы не читал. Так что сиди и читай дальше ;)
Как проводятся SQL-inj?
Вбивай в гугл и ищи статьи всяких разных хакеров. Если искать не умеешь - то дальше не читай, все равно не поймешь.
Как защититься?
Что, нагуглил статей? Может и про защиту написано?
Какие-нибудь леменги вроде Михуила Фленова. фильтровать советуют? Шли нах.
Ничего, повторяю еще раз для альтернативно-одаренных: НИЧЕГО фильтровать не надо. СУБД - на то она и СУБД, а не херня какая-то, чтобы нормально любые данные принимать.
Наша задача - просто правильно эти данные преподнести.
Защищаться надо так(применительно к PHP и mysql):
1) Если поле в базе числовое, то: (int) (ну или intval()). Можно по модулю взять при использовании в LIMIT, но это не секурити-дырка.
2) Если текстовое, то просто mysql_real_escape_string()
3) Всякие magic quotes и подобные затычки отключены. Кто не отключил - ССЗБ(что это означает - смотрите на LOR'е)
И ВСЕ! Больше ничего не надо. Ибо запрос испортить левыми данными нельзя.
Повторю еще раз: НИКАКИХ ФИЛЬТРАЦИЙ.
LIKE/RLIKE/AGAINST/etc - это частный случай, и рассматривается отдельно.
Примера не будет. Если не понял - значит это тебе не надо.
ORM
Что это такое, написано здесь: http://ru.wikipedia.org/wiki/ORM
Защита от SQL-inj - это побочный результат применения данной технологии.
Что касательно защиты от XSS, то никаким образом к БД это не относится.
Так что те, кто хотел это все объединить в 1 функцию(да к тому же и с проверкой) - идите лесом. Это кардинально разные вещи и они друг к другу не относятся.
И да пребудет с вами сила(не со всеми)!
nerezus, 5.01.07-2.01.08
max_pain89
05.01.2007, 20:22
хм довольно странный, даже не статья, а пост.
В защиту magic quotes скажу что если ставишь двиг, не собственно ручно написаный, смысла отключать не вижу, больше риск.
Я сначала хотел что-то из строчек восьми написать )
Но написал больше.
Причина - тема http://forum.antichat.ru/thread30506.html
Ну а чтьо касается magic quotes - то нефиг юзать кривые движки ;)
intval() например при -12 выводит -12. Это не дырка? А вот насчет mysql_real_escape_string() это ты в точку! Нхрена писать невпупенные функции когда можно одной строчкой обойтись.
intval() например при -12 выводит -12. Это не дырка?
Я даже приписал:
"Можно по модулю взять в LIMIT, но это не секурити-дырка."
Извини, пойду лучше учебник по скулю почитаю.
intval() например при -12 выводит -12. Это не дырка? не-а =)
Zadoxlik
05.01.2007, 22:10
Это все ясно, только ты не раскрыл тему=) Например при Selectе с Like надо экранировать еще пару символов, хотя логика очень здравая и самому ни раз мысль такая приходила при прочтении описаний разного рода фильтраций =)
guest3297
06.01.2007, 00:15
А если админы эту статью прочитают ведь все sql иньекции закроют?
Статью в приват!
2[ cash ], тебя как самого умного в подполье работать на сопротивление.
Это все ясно, только ты не раскрыл тему=)
Согласен,
забыли про грамотное распределение прав в СУБД.
вы еще про хранимые функции скажите =)))
Dracula4ever
09.01.2007, 10:49
Чтобы защитится от SQL Injection надо, прежде всего надо распределять по его видам.
К примеру, если мы хотим получить целое число (int) надо чтобы шла проверка что это число и правда целое.
Это можно осуществить с помощью функнии IsNumeric в таком виде:
If (not IsNumeric(Request("ID"))) then ...
Так же надо чтобы не показывались ошибки, которые приводят к взлому сайта.
Есть полно путей сделать это, но помойму лучше всего это осуществить с помощью того, что есть ошибка работа не прекратилась.
номер ошибки error resume next
надо чтобы шла проверка что это число и правда целое Во-первых, никаких проверок не надо! Сколько раз повторять?
Во-вторых, int не может быть не целым!
error_reporing(0);
magic_quotes on
и числа передаваемые базе тоже обрамляем ковычками типо
.. where id ='1'
и хакеры прутся полем
GHostly_FOX
10.01.2007, 07:44
Мой метод защиты:
Если вы передаете только текст и числа в скрипты к примеру:
index.php?modules=news&id=1
то вполне подойдет данный код:
function var_chek($var,$col){
$var = substr($var, 0, $col);
$var = preg_replace("/[^\w\x7F-\xFF\s]/", "", $var);
$good = ereg_replace(" +", " ", $var);
$good = strip_tags($good);
return $good;
}
$modules=var_chek($modules,10);
$id=var_chek($id,5);
Данный код не только удалит все спец символы из передаваемых строк но и обрезает по длинне, ни один XSS или SQL inj... не пройдет через этот фильтр.
GHostly_FOX Воот... прекрысный пример в тему как не надо делать...
Примерно такой же код используется в последних версиях phpbb
так действительно делать не надо.
Лучшим средством будет типизирование параметров - явно прописать в скрипте имена параметров и их типы и соответствующе их парсить. Если int - делать intval(), если string - делать mysql_escape_string.
При выводе всех значений на экран обрамлять в htmlspecialchars, а резать это при передаче в БД - маразм.
Тут я на 100% согласен с nerezus'ом
magic_quotes on Обязательно off.
Т.к. иначе будет двойное экранирование.
И вообще magic_quotes, register_globals и т.д. отменили в PHP6, чтобы криворукие недокодеры не юзали их )
и числа передаваемые базе тоже обрамляем ковычками типо Зачем?
чтобы нельзя было провести инъекцию......из под ковычек не выйти
чтобы нельзя было провести инъекцию А разве без этой штуки можно? подумай хорошенько )
я не про твой способ говорил а про свой, где я указал что простого magic quotes on будет достаточно с обрамленныеми параметрами. Если числа не обрамлять, тогда инъекция возможна.
простого magic quotes on будет достаточно а если тебе попадется нормально настроенный хостинг? или с новой версией пхп(в ближайшем будущем)?
Что, переписывать будешь?
а если тебе попадется нормально настроенный хостинг?
ini_set();
или с новой версией пхп(в ближайшем будущем)?
Я сомневаюсь, что это будет в ближайшем. Ну 2-3 хостера поставят новую версию, остальные врядли.
Что, переписывать будешь?
А хз что придется при новой версии. Сейф-мод улетает. глобальные переменные тоже...вроде новые классы появляются
Так что некоторые куски кода все таки придется переписывать...и это факт. Вобщем когда выйдет, тогда и будем смотреть)
Zadoxlik
10.01.2007, 19:35
С каждым нерезусовым словом в топе согласен :d
k1b0rg, воот: у тебя каждое неправильное решение/костыль тащит за собой еше гору костылей, и они нарастают как снежный ком.
А теперь посмотри на альтернативу(которая, кстати легче): писать правильно.
GHostly_FOX
12.01.2007, 10:11
Воот... прекрысный пример в тему как не надо делать...
Почему же нет?!
Данный код позволяет мне получать чистые данные, на моем сайте в основном передаются только числа и текст... все остальное лишнее и я это убираю...
потому что вместо 10 строчек можно обойтись одной.
blaga. Нет не по этому. У него совсем неправильно.
GHostly_FOX, данные у тебя не "чистые", как ты выразился, а испорченные. Теряем информацию при твоей "обработке".
int и intval() ограничены -2147483648 до 2147483648
а числа большие этому, предлагаешь уже строкой брать? тогда ты пролетишь mysql_real_escape_string тебе не поможет, взломают так что ноги согнутся...
$id=is_numeric($_GET['id'])?$_GET['id']:0;
тебя опять эта запись не устроит? )) is_numeric возьмет любое число)
k1b0rg, спасибо, посмеялся.
А теперь немного подумай. Головой.
Предположим, в движке обрабатываем ее как:
1) ...как строку. Тогда причем int/intval() ?
2) ...как число. Тогда туда и не должны попасть такие значения, а int/intval() обрежет только неправильные.
nc.STRIEM
14.01.2007, 01:29
nerezus молодца! реальн клево отписал! я даж посмеялся! хоть не впадлу читать было, т.к. не много)))
а ваше я обычно все параметры передоваемые в запрос беру в ' ' а в самих параметрах экранирую ' и всегото!))
а ваше я обычно все параметры передоваемые в запрос беру в ' ' а в самих параметрах экранирую ' и всегото!))
ну дык так и надо делать правильно.
mysql_escape_string поможет правильно передать любую строку в базу данных, а intval поможет передать число
nc.STRIEM
14.01.2007, 01:50
а не прощи ли сделать
$str=str_replace("'","\'",$str);
Конечно нет.
запрос можно испортить.
А эта функция экранирует еще и другие символы.
Я уже писал в подобной теме. Зачем создавать громоздкие функции для экранирования запрещенных символов, если все уже давно придумано за нас.
вот пример безопасного кода:
<?php
$val = (int)$_GET['val'];
$val = mysql_escape_string($val);
$q = mysql_query("SELECT id,name,etc FROM table WHERE val = '$val'");
if (!$q)
{
echo '<br>Неверное значение переменной $val';
}
else
{
while ($a = mysql_fetch_array($q))
{
$id = $a['id'];
$name = $a['name'];
$etc = $a['etc'];
$name = htmlspecialchars($name);
$etc = htmlspecialchars($etc);
// вывод результата
}
}
?>
вот.
Почти верно.
Почему почти?
$val = isset($_GET['val']) ? (int)$_GET['val'] : 0;
от инекции да. все верно.
>>но это не секурити-дырка.
бебе от инекции да, но секурити;) тк можно получить раскрытие пути. чем не бага.
ZaCo, а если у меня еррор_репортенг по нулям? :)
На сервере он всегда по нулям ;)
А на девелоперской тачке по максимуму ;)
У меня в голове появилась кощунственная мысль засунуть кусочек кода в скрипт с библиотекой функций/классов чтобы он проводил через себя все 3 массива куков, пост и гет. С каждым элементом он производил определенные действия , а потом засовывал их обратно в массив.
Вопрос насколько это нужно и сильно ли это нагрузит все?
У меня в голове появилась кощунственная мысль засунуть кусочек кода в скрипт с библиотекой функций/классов чтобы он проводил через себя все 3 массива куков, пост и гет. С каждым элементом он производил определенные действия , а потом засовывал их обратно в массив.
Вопрос насколько это нужно и сильно ли это нагрузит все?
что-то типа foreach($_REQUEST as $key=>$value){}
Вопрос насколько это нужно и сильно ли это нагрузит все? Это абсолютно не нужно. Второй вопрос тебя не должен волновать.
что-то типа foreach($_REQUEST as $key=>$value){}
Скрипт составить не проблема, вопрос в том, нужно ли это делать, т.е. предпочтительней "мыть" входящие данные на входе по-отдельности или все сразу. Исходя из вышестоящего поста можно стелать вывод, что путь наибольшей головной боли предпочтительней ;)
Какой нафиг головной боли? Делай, как я написал, и ее не будет совсем. Нахрен тебе портить данные?
Была бы статья о всех методах защиты....был бы большой плюс
intro
В этой небольшой статье я расскажу о защите о всем нам известной уязвимости SQL-injection. Данной уязвимости подвержено подавляющее большинство сайтов в сети. Суть уязвимости заключается в отсутствии фильтрации спецсимволов в параметрах, передаваемых в запросах к БД. Уязвимость позволяет злоумышленнику выполнять запросы к БД… Да лан, чё я рассказываю. В разделе статьи полно информации по SQL-injection и я изобретать велосипед не буду. Ну что ж, перейдём к сути…
Метод №1 – Фильтрация
Этот метод заключается в фильтрации спецсимволов с помощью стандартной функции preg_match(). Данная функция будет обрабатывать параметры, передаваемые скрипту от пользователя, на соответствие параметрам, которые должны быть в запросе. Вот кусок уязвимого скрипта:
…
if(!empty($_GET['id']))
{
/*Получение нужной статьи из БД*/
$query = "SELECT * FROM articles WHERE id = '$_GET[id]'";
$result_query = mysql_query($query);
if (!$result_query) exit("Bad parametr");
if ($article = mysql_fetch_array($result_query))
{
…
А вот тот же код, только с использованием функции preg_match():
…
if(!empty($_GET['id']))
{
/*Проверка переданного параметра*/
if (preg_match("|^[\d]{1,3}$|", $_GET['id']))
{
/*Получение из БД нужной статьи*/
$query = "SELECT * FROM articles WHERE id = '$_GET[id]'";
$result_query = mysql_query($query);
if (!$result_query) exit("Bad parametr");
if ($article = mysql_fetch_array($result_query))
{
…
else
{
/*Получение из БД всех статей*/
$query = "SELECT * FROM articles";
$result_query = mysql_query($query);
if (!$result_query) exit("Bad parametr");
while ($article = mysql_fetch_array($result_query))
{
…
Согласитесь, не сложно написать пару лишних строк в скрипт, которые смогут защитить ваш сайт от атаки.
Некоторые перци обрабатывают параметр функцией mysql_escape_ptring(), она похожа на addslashes(). Лично я такой подход не уважаю. Этот способ можно использовать лиш как способ записи корректных SQL запросов и не более того. Многие используют фцнкцию str_replace() которая вырезает все спецсимволы в параметре. Но при использование данной функции запрос всё равно будет выполнен с ложными данными, и вызовет туеву хучу ошибок.
Способ №2 – создание собственной функции обращения к БД
Согласитесь, каждый раз добавлять preg_match достаточно нудное занятие, есть способ как этого избежать. Можно написать свою функцию , которая будет отправлять запросы к БД. Вот пример от Дмитрия Котерова, библиотека содержащая в себе функцию для защиты нашего скрипта. Суть её работы в том, что она заменяет стандартную и всем нам до боли известную функцию mysql_query() своей mysql_qw(), т.е. в либе он создал функцию, заменяющую mysql_query, в которую сразу встроена проверка спецсимволов, а так же HTML-тэгов. Данный скрипт защищает как от SQL-injection, так и от XSS. Вот код библиотеки:
<?php ## Простейшая функция для работы с placeholder-ами.
// result-set mysql_qw($connection_id, $query, $arg1, $arg2, ...)
// - или -
// result-set mysql_qw($query, $arg1, $arg2, ...)
// Функция выполняет запрос к MySQL через соединение, заданное как
// $connection_id (если не указано, то через последнее открытое).
// Параметр $query может содержать подстановочные знаки ?,
// вместо которых будут подставлены соответствующие значения
// аргументов $arg1, $arg2 и т.д. (по порядку), экранированные и
// заключенные в апострофы.
function mysql_qw() {
// Получаем все аргументы функции.
$args = func_get_args();
// Если первый параметр имеет тип "ресурс", то это ID соединения.
$conn = null;
if (is_resource($args[0])) $conn = array_shift($args);
// Формируем запрос по шаблону.
$query = call_user_func_array("mysql_make_qw", $args);
// Вызываем SQL-функцию.
return $conn!==null? mysql_query($query, $conn) : mysql_query($query);
}
// string mysql_make_qw($query, $arg1, $arg2, ...)
// Данная функция формирует SQL-запрос по шаблону $query,
// содержащему placeholder-ы.
function mysql_make_qw() {
$args = func_get_args();
// Получаем в $tmpl ССЫЛКУ на шаблон запроса.
$tmpl =& $args[0];
$tmpl = str_replace("%", "%%", $tmpl);
$tmpl = str_replace("?", "%s", $tmpl);
// После этого $args[0] также окажется измененным.
// Теперь экранируем все аргументы, кроме первого.
foreach ($args as $i=>$v) {
if (!$i) continue; // это шаблон
if (is_int($v)) continue; // целые числа не нужно экранировать
$args[$i] = "'".mysql_escape_string($v)."'";
}
// На всякий случай запорняем 20 последних аргументов недопустимыми
// значениями, чтобы в случае, если число "?" превышает количество
// параметров, выдавалась ошибка SQL-запроса (поможет при отладке).
for ($i=$c=count($args)-1; $i<$c+20; $i++)
$args[$i+1] = "UNKNOWN_PLACEHOLDER_$i";
// Формируем SQL-запрос.
return call_user_func_array("sprintf", $args);
}
?>
Используется он так
include_once( "./mysq_qw.php" );
…
if(!empty($_GET['id']))
{
/*Получение нужной статьи из БД*/
$query = "SELECT * FROM articles WHERE id = '$_GET[id]'";
$result_query = mysql_qw($query);
if (!$result_query) exit("Bad parametr");
if ($article = mysql_fetch_array($result_query))
{
…
Конечно он староват, но работает до сих пор…
Способ №3 – Использование mod_rewrite
Этот способ заключается в использовании модуля Апача под названием mod_rewrite. И так, как же мы его будем использовать??? :D Все знаю как данные передаются скрипту методом GET (www.site.ru/script.php?id=1), где id содержит параметры для обращения к БД. С использование mod_rewrite можно выше приведённой ссылке придать более человеческий вид (Например: www.site.ru/script_1.html). Для этого на нужно в веб-каталоге сервера (Например: /home/site/www) создать файл .htaccess со следующим кодом:
RewriteEngine on
Options +FollowSymlinks
RewriteBase /
RewriteRule ^.htaccess$ - [F]
Таким образом мы будем запускать модуль. Теперь перейдем к замене ссылок. Добавим в конец .htaccess следующую строку:
RewriteRule http://www.site.ru/script_([0-9]*).html http://www.site.ru/script.php?id=$1
Теперь при обращении к сайту www.site.ru/script_1.html произойдёт замена на http://www.site.ru/script.php?id=1, которая в последствии будет выполнена. “А в чём же здесь защита?” спросите вы. Обратите внимание на script_([0-9]*).html, здесь у нас идёт проверка переданных скрипту параметров, т.е. как мы видим: если передаваемый параметр будет содержать кроме числовых ещё какие-нибудь символы, то запрос выполнен не будет…
Дополнительную информацию о mod_rewrite и о его использовании можно найти в документации по серверу Apache. www.apache.org
Outro
Ну вот, я кратко описал способы решения данной проблемы. Если вам есть что добавить, просьба отписать в эту тему. Всем удачи.
FraiDex
НИЧЕГО фильтровать не надо. СУБД - на то она и СУБД, а не херня какая-то, чтобы нормально любые данные принимать.
фаг.. но ведь вё равно принимает. спецсимволы она не фильтрует
фаг.. но ведь вё равно принимает. спецсимволы она не фильтрует
mysql_real_escape_string -- Экранирует специальные символы в строках для использования в выражениях SQL
Достаточно прогонять текстовые переменные по даной функции и больше не чего не надо
function secure_sql($value) {
if( get_magic_quotes_gpc()) {
$value = stripslashes( $value );
}
if( function_exists( "mysql_real_escape_string" )) {
$value = mysql_real_escape_string( $value );
} else {
$value = addslashes( $value );
}
return $value;
}
Достаточно прогонять текстовые переменные по даной функции и больше не чего не надо
function secure_sql($value) {
if( get_magic_quotes_gpc()) {
$value = stripslashes( $value );
}
if( function_exists( "mysql_real_escape_string" )) {
$value = mysql_real_escape_string( $value );
} else {
$value = addslashes( $value );
}
return $value;
}
На вид большая функция а =\\
1) Зачем цифры переводить через эту функцию?
Достаточно
<?php
$xek = intval($xek);
?>
2) Оох... где-то еще есть серваки с пхп 3 чтобы делать поверку на существование функции mysql_real_escape_string ?
3) mysql_real_escape_string не экранирует символы % и _ также как mysql_escape_string что будет багой например при %LIKE% .....
Поэтому достаточно написать свою функцию в 3 строки с реплейсом % и _ на \%, \_ ну и mysql_real_escape_string
На вид большая функция а =\\
1) Зачем цифры переводить через эту функцию?
Достаточно
<?php
$xek = intval($xek);
?>
зри в корень )
Сообщение от DIAgen
Достаточно прогонять текстовые переменные по даной функции и больше не чего не надо
Могу скинуть свою обертку для запросов. Нужно?
На самом деле это боян, обертка типа.
...
$val = (int)$_GET['val'];
$val = mysql_escape_string($val);
....
А зачем число ещё и mysql_escape_string'ом обрабатывать?
Krist_ALL
04.09.2009, 20:19
Mysql_real_escape_string не спасет от слепых инекций.
Mysql_real_escape_string не спасет от слепых инекций.
А не от слепых спасает?:о
aleksej_sumarok
19.09.2009, 13:39
Могу скинуть свою обертку для запросов. Нужно?
На самом деле это боян, обертка типа.
Если не трудно скинь пожалуйста :)
Pashkela
27.09.2009, 21:59
в топике ничего не упомянуто об:
1. реферере
2. сессии
3. прочие "особые" моменты
))
Практически никто этого не обрабатывает, если говорить про фул_паф_дискложен
Pashkela, ну я думал, что понятно, что нельзя доверять любому вводу )
Если не трудно скинь пожалуйста Его уже не осталось, да и не нужен он - это было слабое подобие Zend_Db
Pashkela, ну я думал, что понятно, что нельзя доверять любому вводу )
Его уже не осталось, да и не нужен он - это было слабое подобие Zend_Db
Кстати,если уж дело зашло до Zend_Db, добавлю от себя отличный мануал по этой "обертке".
http://docs.huihoo.com/php/zend/ZendFramework-0.1.5/documentation/end-user/ru/zend.db.html
Читать очень легко,нет никаких супер-слов,все коды комментируються.В общем осваивайте,я сам остановился именно на Zend_Db.
Кстати,если уж дело зашло до Zend_Db, добавлю от себя отличный мануал по этой "обертке".
http://docs.huihoo.com/php/zend/ZendFramework-0.1.5/documentation/end-user/ru/zend.db.html Чем же мануал по 0.1.5 версии актуальнее актуального 1.9.x на оффсайте?)))
Чем же мануал по 0.1.5 версии актуальнее актуального 1.9.x на оффсайте?)))
Тем,что он короче,и понятнее)
Хотя,кому как,лично мне в свое время было проще прочитать тот ман,чем офф :) Ибо много еще не понимал
Статья про анти sql-inj, а ачат - анти хак сайт,
а и ещё осталось не писать сплоиты, а исправлять баги веб приложений
Gray_Wolf
28.09.2009, 13:02
Статья про анти sql-inj, а ачат - анти хак сайт,
а и ещё осталось не писать сплоиты, а исправлять баги веб приложений
Вообщето ачат это сайт по аудиту безопасности.
Так что всё верно...
Ничего не сказано про prepared statement'ы. Именно из-за их использования ORM движки обладают побочным эффектом защиты от sql-inj.
Ничего не сказано про prepared statement'ы. Именно из-за их использования ORM движки обладают побочным эффектом защиты от sql-inj. Ну это личные внутренности ОРМ, он может и по типу эскейпить просто. ;)
НО про них надо в другом месте сказать, обновлю )
Gray_Demon
12.11.2009, 06:46
Уже на многих ру хостах юнион селект рубают , надежда ток на кавычку и знание движка(((
Уже на многих ру хостах юнион селект рубают Не верю. Если и есть такие, то это единичные случаи за "2 бакса в год", т.к. юнион селект полезен и юзается активно.
phpdreamer
18.12.2009, 18:17
что думаете про такой подход?
function antihack () {
$uri = $_SERVER['REQUEST_URI']; //определяем адрес запрашиваемой страницы
$arr_u = explode("?", $uri ); //разделяем адрес на массив
$url = $arr_u[0]; //того что до знака ?
$p_url = $arr_u[1]; // и того что после
$inj='/script|http|<|>|<|>|SELECT|UNION|UPDATE|AND|exe|exec|INSERT|tmp/i'; //это паттерн возможных типов атак в адресе (их можно дополнить своими)
if (preg_match($inj, $p_url )) { // ищем патерн в нашем адресе, в том что за знаком ?
die("Hacking attempt!"); //если находим - посылаем куда подальше :=)
}
}
взято с http://phpmaster.su/php-faq/8-kak-zashhititsya-ot-sql-inekcij-xss-atak-na-php.html
много чего можно добавить к этому коду, но сам подход..?
phpdreamer, провальный подход. Первый пост читай, там ВСЁ описано.
Nightmarе
18.12.2009, 18:27
что думаете про такой подход?
взято с http://phpmaster.su/php-faq/8-kak-zashhititsya-ot-sql-inekcij-xss-atak-na-php.html
много чего можно добавить к этому коду, но сам подход..?
..с новым подходом....
Ты так никогда не защитишься. при SQL проскочит любой твой отфильтрованный контент в разном регистре UnIoN и т.д... буква i вообще может в переменной оказаться по делу, а фильтранётся =))) ну и про HEX, URL и другие виды кодировки не забывай =)))
А в первом посте всё изложенно.
phpdreamer
18.12.2009, 18:37
спасибо, теперь разобрался
при SQL проскочит любой твой отфильтрованный контент в разном регистре UnIoN
Не соглашусь, сейчас пробывал в опере 10 набрать в get параметре это => "SeLEcT" (без ковычек), итог => не проскочило слово
Вообще да, плохая защита
что думаете про такой подход?
Это ппц.
Засунуть в коммент в скл-инъекции знак "?" - вот и весь обход "фильтрации":
?lala=-1+/*?*/union+select+...
(;
Nightmarе
Буква "i" в той регулярке - модификатор...
phpdreamer
18.12.2009, 20:05
Это ппц.
Засунуть в коммент в скл-инъекции знак "?" - вот и весь обход "фильтрации":
?lala=-1+/*?*/union+select+...
(;
Nightmarе
Буква "i" в той регулярке - модификатор...
я тоже сразу подумал что надо проверять еще count массива... вопрос был не о том, но больше вопросов нет =)
Скули обречены на вымирание :)
Юзайте mysqli и ничего фильтровать не надо и искейпить тоже не надо ничего.
$mysqli = new mysqli();
$mysqli->prepare("select * from data where id = ?");
и далее по тексту :)
А если так использовать можно избежать xss/sqli???
function secure($par) {
$numb = array("1","2","3","4","5","6","7","8","9","0","-");
if( get_magic_quotes_gpc())
{
$link = stripslashes($par);
}
$l=$par+1-1;
if ((string)$l==(string)$par) {
$par=(string)$par;
$new_par="";
for ($i=0;$i<>strlen($par);$i++) {
if (in_array($par{$i},$numb)) {
$new_par=$new_par.$par{$i};
}
if ($new_par<"-2147483648" || $new_par>"2147483647") $new_par="1";
$new_par=(int)$new_par;
}
}
else
{
$new_par=mysql_real_escape_string($par);
}
return $new_par;
}
Так вроде и раскрытия путей не будет
А где проверка на то что $par может быть массив?
А если так использовать можно избежать xss/sqli??? Самый говнокодистый говнокод в этой теме.
Самый говнокодистый говнокод в этой теме.
На самом деле это не просто самый говнокодистый говнокод, это код который не работает и не имеет смысла!
И это меня заставило подумать о том что писал nerezus в первом посте.
Когда я искал инъекции на различных сайтах меня смущало то, что когда я открываю страницу site.com/news.php?id=1 и добавляю к примеру +1+1+1, то у меня открывается та же страница, что и при id=1. Ну и что я надумал: если запрос вида SELECT * FROM TABLE WHERE id='.$id.', а в базе параматр id целочисленный, то наверно где то идёт конвертация значения id из строки в число. Единственное моё обьяснение так это конвертация процедурой похожей на процедуру val в Delphi( procedure Val ( const NumberString : string; var NumberVar : Number Type; var ErrorCode : Integer ) ), где ErrorCode - позиция с начиная с которой нельзя сконвертировать строку. Как я понял СУБД обрезает строку начиная с параметра ErrorCode и до конца, в итоге и получается id=1. nerezus сказал, что надо использовать mysql_real_escape_string() в текстовых полях и не изобретать какие-либо фильтры и т.д и т.п. Это нужно для того чтобы не нарушился синтаксис sql при добавлении '. По моему стоит эту функцию использовать и для числовых значений, и главное чтобы запрос был вида SELECT * FROM TABLE WHERE id='.$id.', потому что тогда параметр id передаётся строкой и субд ковертирует id в integer. Если будет запрос вида SELECT * FROM TABLE WHERE id=$id, тогда, как я понял не идёт проверка на принадлежность $id к числовому типу. Если я ошибаюсь, то поправьте, а то заведу кого-нибудь в заблуждение этим постом...
draliokero
04.04.2010, 00:04
Может пригодиться кому-нибудь использованный мной контрацептив моих проектов:
<?php
$server = "localhost";
$database = "databasename";
$dbuser = "root";
$dbpass = "";
$email = "";
$con = mysql_connect($server, $dbuser, $dbpass);
mysql_select_db($database, $con);
// создание таблицы
$tableSchema = array();
$tableSchema[] = "CREATE DATABASE IF NOT EXISTS " . $database . "";
$tableSchema[] = "CREATE TABLE IF NOT EXISTS " . $database . ".`logger_logs` (
`name` INT( 10 ) NOT NULL ,
`attack_type` VARCHAR( 200 ) NOT NULL ,
`page` VARCHAR( 200 ) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE = MYISAM";
foreach($tableSchema as $table) {
mysql_query($table);
}
// КОНЕЦ создание таблицы (после выполнения запроса, желательно удалить этот блок кода)
$username = $_SERVER['REMOTE_ADDR'];
$action[0] = "";
$no = 0;
$full_attack_type = "";
foreach($_REQUEST as $var => $value) {
$action[$no] = $value;
$no = $no + 1;
} // $_REQUEST checks for post, get cookie & file
for($i = 0; $i < $no; $i++) {
$attacktype = "";
// first check for XSS (BASIC checks... easily evaded) doesn't need to be fullproof only for logger, site is vulnerable anyway!
if (preg_match('/((\%3C)|<)((\%2F)|\/)*[a-z0-9\%]+((\%3E)|>)/ix ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/((\%3C)|<)((\%69)|i|(\%49))((\%6D)|m|(\%4D))((\%67)|g|(\%47 ))[^\n]+((\%3E)|>)/i ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/src=.*?|alert|script|javascript\:|\.js|charset\=|w indow\.|document\.|\.cookie|<script|<xss|base64/i ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/((\%3C)|<)[^\n]+((\%3E)|>)/i ', $action[$i])) {
$attacktype = "Cross site scripting";
}
// check for crlf/http response splitting
if (preg_match('/%0a|%0d|\\\r|\\\n|\n|\r/i', $action[$i])) {
$attacktype = "CRLF injection";
}
// check for sql injection
if (preg_match('/(\%27)|(\')|(\-\-)|(\%23)|(\#)/ix', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/((\%3D)|(=))[^\n]*((\%27)|(\')|(\-\-)|\*|(\%3B)|(;))/i ', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/\w*((\%27)|(\'))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix ', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/(()|(\%27)|(\'))union|select|insert|update|delete| drop/ix', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/exec(\s|\+)+(s|x)p\w+/ix ', $action[$i])) {
$attacktype = "SQL injection";
}
// check for remote file inclusion
if (preg_match('(http|https|ftp|www)', $action[$i])) {
$attacktype = "Remote file inclusion";
}
// check for local file inclusion
if (preg_match('/\.\./', $action[$i])) {
$attacktype = "Local file inclusion";
}
// check for null byte attack
$non_null = str_replace("\\0", 'NULL byte detected', $action[$i]);
if (preg_match('/NULL byte detected/', $non_null)) {
$attacktype = "Poison null byte";
$non_null = "";
}
// check for email injection
if (preg_match('/cc:|Content-Type:|to:/ix', $action[$i])) {
$attacktype = "Email header injection";
}
// check for server side includes
if (preg_match('/<!--#.*?--\s*>/i', $action[$i])) {
$attacktype = "Server side include";
}
// check for buffer overflow
if (strlen($action[$i]) > 255) {
$attacktype = "Buffer overflow (>255 chars)";
}
if ($attacktype <> "") {
if ($full_attack_type == "") {
$full_attack_type = $attacktype;
} else {
$full_attack_type = $full_attack_type . "<br />" . $attacktype;
}
}
}
setcookie("flood", $full_attack_type, time() + 180);
if ($full_attack_type <> "") {
if ($_COOKIE["flood"] != $full_attack_type) {
$attacked_page = substr($_SERVER["SCRIPT_NAME"], strrpos($_SERVER["SCRIPT_NAME"], "/") + 1);
mysql_query("INSERT INTO logger_logs ( name, attack_type, page, date) VALUES (INET_ATON('$username'), '$full_attack_type', '$attacked_page', NOW())");
mysql_close($con);
if ($email <> "") {
mail($email, "hack attempt", $username . " tried " . $full_attack_type . " on " . $attacked_page);
}
} else {
die('<html><head><title>Achtung! Hacking attempt: ' . $full_attack_type . '</title><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"></head><body><script language="JavaScript" type="text/javascript" src="http://www.anekdot.ru/rss/random.html"></script></body></html>');
}
die("Achtung! Hacking attempt: " . $full_attack_type); //<-- debug
}
?>
draliokero Вы вообще первый пост читали? А попробуйте, перестанете херь писать
Jokester
04.04.2010, 01:57
<?php
$server = "localhost";
$database = "databasename";
$dbuser = "root";
$dbpass = "";
$email = "";
$con = mysql_connect($server, $dbuser, $dbpass);
mysql_select_db($database, $con);
// создание таблицы
$tableSchema = array();
$tableSchema[] = "CREATE DATABASE IF NOT EXISTS " . $database . "";
$tableSchema[] = "CREATE TABLE IF NOT EXISTS " . $database . ".`logger_logs` (
`name` INT( 10 ) NOT NULL ,
`attack_type` VARCHAR( 200 ) NOT NULL ,
`page` VARCHAR( 200 ) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE = MYISAM";
foreach($tableSchema as $table) {
mysql_query($table);
}
// КОНЕЦ создание таблицы (после выполнения запроса, желательно удалить этот блок кода)
$username = $_SERVER['REMOTE_ADDR'];
$action[0] = "";
$no = 0;
$full_attack_type = "";
foreach($_REQUEST as $var => $value) {
$action[$no] = $value;
$no = $no + 1;
} // $_REQUEST checks for post, get cookie & file
for($i = 0; $i < $no; $i++) {
$attacktype = "";
// first check for XSS (BASIC checks... easily evaded) doesn't need to be fullproof only for logger, site is vulnerable anyway!
if (preg_match('/((\%3C)|<)((\%2F)|\/)*[a-z0-9\%]+((\%3E)|>)/ix ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/((\%3C)|<)((\%69)|i|(\%49))((\%6D)|m|(\%4D))((\%67)|g|(\%47 ))[^\n]+((\%3E)|>)/i ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/alert|script|\.js/i ', $action[$i])) {
$attacktype = "Cross site scripting";
} elseif (preg_match('/((\%3C)|<)[^\n]+((\%3E)|>)/i ', $action[$i])) {
$attacktype = "Cross site scripting";
}
// check for crlf/http response splitting
if (preg_match('/%0a|%0d|\\\r|\\\n|\n|\r/i', $action[$i])) {
$attacktype = "CRLF injection";
}
// check for sql injection
if (preg_match('/(\%27)|(\')|(\-\-)|(\%23)|(\#)/ix', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/((\%3D)|(=))[^\n]*((\%27)|(\')|(\-\-)|\*|(\%3B)|(;))/i ', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/\w*((\%27)|(\'))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix ', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/(()|(\%27)|(\'))union|select|insert|update|delete| drop/ix', $action[$i])) {
$attacktype = "SQL injection";
} elseif (preg_match('/exec(\s|\+)+(s|x)p\w+/ix ', $action[$i])) {
$attacktype = "SQL injection";
}
// check for remote file inclusion
if (preg_match('(http|https|ftp|www)', $action[$i])) {
$attacktype = "Remote file inclusion";
}
// check for local file inclusion
if (preg_match('/\.\./', $action[$i])) {
$attacktype = "Local file inclusion";
}
// check for null byte attack
$non_null = str_replace("\\0", 'NULL byte detected', $action[$i]);
if (preg_match('/NULL byte detected/', $non_null)) {
$attacktype = "Poison null byte";
$non_null = "";
}
// check for email injection
if (preg_match('/cc:|Content-Type:|to:/ix', $action[$i])) {
$attacktype = "Email header injection";
}
// check for server side includes
if (preg_match('/<!--#.*?--\s*>/i', $action[$i])) {
$attacktype = "Server side include";
}
// check for buffer overflow
if (strlen($action[$i]) > 255) {
$attacktype = "Buffer overflow (>255 chars)";
}
if ($attacktype <> "") {
if ($full_attack_type == "") {
$full_attack_type = $attacktype;
} else {
$full_attack_type = $full_attack_type . "<br />" . $attacktype;
}
}
}
setcookie("flood", $full_attack_type, time() + 180);
if ($full_attack_type <> "") {
if ($_COOKIE["flood"] != $full_attack_type) {
$attacked_page = substr($_SERVER["SCRIPT_NAME"], strrpos($_SERVER["SCRIPT_NAME"], "/") + 1);
mysql_query("INSERT INTO logger_logs ( name, attack_type, page, date) VALUES (INET_ATON('$username'), '$full_attack_type', '$attacked_page', NOW())");
mysql_close($con);
if ($email <> "") {
mail($email, "hack attempt", $username . " tried " . $full_attack_type . " on " . $attacked_page);
}
} else {
die('<html><head><title>Achtung! Hacking attempt: ' . $full_attack_type . '</title><meta http-equiv="Content-Type" content="text/html; charset=windows-1251"></head><body><script language="JavaScript" type="text/javascript" src="http://www.anekdot.ru/rss/random.html"></script></body></html>');
}
die("Achtung! Hacking attempt: " . $full_attack_type); //<-- debug
}
include ($aaaa);
?>
strashnaya_beda.php?aaaa=data:;base64,PD9waHAgcGhw aW5mbygpOyA/Pg
пиу-пиу, наши победили
ЗЫ Код супер, было страшно :(
draliokero
04.04.2010, 02:05
Gifts, в первом посте, вроде как, не запретили продолжать писать херь. Тема не закрыта - значит, себя не исчерпала. Бывает, когда нужно по-дружески, за пивасик развернуть что-нибудь буржуйскими скриптами, вот тут думаю с типами не стоит мозг себе трахать.
Jokester, Whoa! Спасибо, не заметил и не у всех ini_set("allow_url_include", "0"); проставлен!
заменил
} elseif (preg_match('/alert|script|\.js/i ', $action[$i])) {
на
} elseif (preg_match('/src=.*?|alert|script|javascript\:|\.js|charset\=|w indow\.|document\.|\.cookie|<script|<xss|base64/i ', $action[$i])) {
Можно еще как-нибудь закодировать?
Jokester
04.04.2010, 13:25
Можно еще как-нибудь закодировать?
Да, разумеется.
strashnaya_beda.php?aaaa=php://input
POST
<?php phpinfo(); ?>
Думаю есть ещё варианты, но копать лень. Это самое очевидное.
Тебе правильно сказали, завязывай с фильтрацией, сила не в ней, а в правильной обработке переменных.
Всего не учтёшь, как видишь
Насчет полной фильтрации всего, то это хрень, согласен с 1 постом. Сложно, неэффективно, да и попросту не изящно. А при вдруг необходимой отладке дней через n-надцать, будете смотреть на 8кб фильтр как олень.
Как вариант, система аутентификации пользователя. Обламываем любую иньекцию, причем не фильтруя ни один символ, просто заворачивая в хеш принятые от юзера логин\пароль.
Например так:
$hash="";
if(isset($_POST["login"]) && isset($_POST["pass"]) isset($_POST["submit"])){
$hash=md5(trim($_POST["login"])).md5(trim($_POST["pass"]));
}else die("Good luck.");
просто заворачивая в хеш принятые от юзера логин\пароль
круто, действительно очень очень круто
давай тогда сразу
<?php
array_map("md5", $_REQUEST);
?>
и в бд всё записывать в md5, и читать всё в мд5 =\\\
Не надо быть психопатом-параноиком. Секурити-фичи должны не только отсеивать все возможные баги, но и не влиять пагубно на оптимизацию кода.
Если говорить исключительно о анти sql-inj то имхо тема раскрыта на 99%, и ничего другого выдумывать не надо
А юзание фильтра запросов на 8кг разве не влияет на оптимизацию?
Ну я, вроде бы, написал что тема раскрыта, если её внимательно почитать то написано что фильтровать не надо, и фильтров "по 8кг" быть не должно
И далее оффтоп
$hash=md5(trim($_POST["login"])).md5(trim($_POST["pass"]));
представим что данные сверяются в бд, и в бд 1 колонка в которой первые 32 байта это md5 логина, следующие 32 это md5 пасса, представь сорцы админки, и запрос к бд который например меняет пароль, или логин?
UPDATE `shit` SET wtf=(concat('".md5(new_login)."', (SELECT substring(wtf, 33)))) WHERE id=1;
чуть-чуть бред да?
А юзание фильтра запросов на 8кг разве не влияет на оптимизацию? Причем при каждом селекте, инсерте, апдейте...
К тому же это была именно аутентификация, а не юзание всего и вся.
Ну я, вроде бы, написал что тема раскрыта, если её внимательно почитать то написано что фильтровать не надо, и фильтров "по 8кг" быть не должно
Если внимательно почитать мой пост, то там написано что хеш используется именно в том случае, но вам это не помешало мягко гря "потроллить".
Тема касается анти sql-inj, но если продолжаем то...
Оффтоп:
$old_login = substr($hash,0,32);
$old_pass = substr($hash,32);
$hash = md5($new_login).md5($new_pass);
o4zloy два запроса вместо одного, и следует напомнить, что md5 не самый быстрый алгоритм
Смысл темы не в том, чтобы защитить данное конкретное обращение к БД (да, мд5 от введенных данных будет работать). А чтобы приучить к правильному подходу к работе с СУБД в целом. Вместо того чтобы выдумывать костыль под каждый запрос, нужно просто правильно обрабатывать данные
o4zloy два запроса вместо одного, и следует напомнить, что md5 не самый быстрый алгоритм
Почему два?
Если, в базе находим этот хеш, значит юзер прошел проверку логина\пароля.
Насчет быстродействия, при входе на ресурс, все равно идет проверка пароля, и используют хеширование(двойное, а иногда и тройное) или это не так?)
Почему бы не совместить, с пользой для дела, полностью исключив при этом потенциальную дыру(в случае отсутствия защиты).
Смысл темы не в том, чтобы защитить данное конкретное обращение к БД.
А чтобы приучить к правильному подходу к работе с СУБД в целом.
Ммм...в целом? Тема вряд ли осилит такие масштабы, не на один том получится.
По моему, тема посвящена формированию правильной выборки из бд без возможности нарушения запроса неверными данными от юзера.
Конкретный пример, был приведен как вариант полного исключения нарушения запроса, он не претендует на лавры образцово-показательного, и уж тем более как шаблон всех запросов к бд.
vBulletin® v3.8.14, Copyright ©2000-2026, vBulletin Solutions, Inc. Перевод: zCarot