PDA

Просмотр полной версии : Статья про анти sql-inj


nerezus
05.01.2007, 20:01
Статья про защиту от 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 скажу что если ставишь двиг, не собственно ручно написаный, смысла отключать не вижу, больше риск.

nerezus
05.01.2007, 21:06
Я сначала хотел что-то из строчек восьми написать )
Но написал больше.
Причина - тема http://forum.antichat.ru/thread30506.html

Ну а чтьо касается magic quotes - то нефиг юзать кривые движки ;)

blaga
05.01.2007, 21:28
intval() например при -12 выводит -12. Это не дырка? А вот насчет mysql_real_escape_string() это ты в точку! Нхрена писать невпупенные функции когда можно одной строчкой обойтись.

nerezus
05.01.2007, 21:39
intval() например при -12 выводит -12. Это не дырка?
Я даже приписал:
"Можно по модулю взять в LIMIT, но это не секурити-дырка."

blaga
05.01.2007, 21:40
Извини, пойду лучше учебник по скулю почитаю.

_Great_
05.01.2007, 21:49
intval() например при -12 выводит -12. Это не дырка? не-а =)

Zadoxlik
05.01.2007, 22:10
Это все ясно, только ты не раскрыл тему=) Например при Selectе с Like надо экранировать еще пару символов, хотя логика очень здравая и самому ни раз мысль такая приходила при прочтении описаний разного рода фильтраций =)

guest3297
06.01.2007, 00:15
А если админы эту статью прочитают ведь все sql иньекции закроют?
Статью в приват!

blaga
06.01.2007, 06:44
2[ cash ], тебя как самого умного в подполье работать на сопротивление.

Xex
09.01.2007, 04:50
Это все ясно, только ты не раскрыл тему=)
Согласен,
забыли про грамотное распределение прав в СУБД.

nerezus
09.01.2007, 10:27
вы еще про хранимые функции скажите =)))

Dracula4ever
09.01.2007, 10:49
Чтобы защитится от SQL Injection надо, прежде всего надо распределять по его видам.
К примеру, если мы хотим получить целое число (int) надо чтобы шла проверка что это число и правда целое.
Это можно осуществить с помощью функнии IsNumeric в таком виде:
If (not IsNumeric(Request("ID"))) then ...

Так же надо чтобы не показывались ошибки, которые приводят к взлому сайта.
Есть полно путей сделать это, но помойму лучше всего это осуществить с помощью того, что есть ошибка работа не прекратилась.
номер ошибки error resume next

nerezus
09.01.2007, 14:09
надо чтобы шла проверка что это число и правда целое Во-первых, никаких проверок не надо! Сколько раз повторять?
Во-вторых, int не может быть не целым!

k1b0rg
09.01.2007, 14:56
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... не пройдет через этот фильтр.

nerezus
10.01.2007, 08:04
GHostly_FOX Воот... прекрысный пример в тему как не надо делать...

k1b0rg
10.01.2007, 10:38
Примерно такой же код используется в последних версиях phpbb

_Great_
10.01.2007, 11:47
так действительно делать не надо.
Лучшим средством будет типизирование параметров - явно прописать в скрипте имена параметров и их типы и соответствующе их парсить. Если int - делать intval(), если string - делать mysql_escape_string.
При выводе всех значений на экран обрамлять в htmlspecialchars, а резать это при передаче в БД - маразм.
Тут я на 100% согласен с nerezus'ом

nerezus
10.01.2007, 15:00
magic_quotes on Обязательно off.
Т.к. иначе будет двойное экранирование.

И вообще magic_quotes, register_globals и т.д. отменили в PHP6, чтобы криворукие недокодеры не юзали их )

и числа передаваемые базе тоже обрамляем ковычками типо Зачем?

k1b0rg
10.01.2007, 17:44
чтобы нельзя было провести инъекцию......из под ковычек не выйти

nerezus
10.01.2007, 18:13
чтобы нельзя было провести инъекцию А разве без этой штуки можно? подумай хорошенько )

k1b0rg
10.01.2007, 18:42
я не про твой способ говорил а про свой, где я указал что простого magic quotes on будет достаточно с обрамленныеми параметрами. Если числа не обрамлять, тогда инъекция возможна.

nerezus
10.01.2007, 18:53
простого magic quotes on будет достаточно а если тебе попадется нормально настроенный хостинг? или с новой версией пхп(в ближайшем будущем)?

Что, переписывать будешь?

k1b0rg
10.01.2007, 19:29
а если тебе попадется нормально настроенный хостинг?
ini_set();

или с новой версией пхп(в ближайшем будущем)?

Я сомневаюсь, что это будет в ближайшем. Ну 2-3 хостера поставят новую версию, остальные врядли.

Что, переписывать будешь?
А хз что придется при новой версии. Сейф-мод улетает. глобальные переменные тоже...вроде новые классы появляются
Так что некоторые куски кода все таки придется переписывать...и это факт. Вобщем когда выйдет, тогда и будем смотреть)

Zadoxlik
10.01.2007, 19:35
С каждым нерезусовым словом в топе согласен :d

nerezus
10.01.2007, 21:15
k1b0rg, воот: у тебя каждое неправильное решение/костыль тащит за собой еше гору костылей, и они нарастают как снежный ком.

А теперь посмотри на альтернативу(которая, кстати легче): писать правильно.

GHostly_FOX
12.01.2007, 10:11
Воот... прекрысный пример в тему как не надо делать...

Почему же нет?!
Данный код позволяет мне получать чистые данные, на моем сайте в основном передаются только числа и текст... все остальное лишнее и я это убираю...

blaga
12.01.2007, 10:26
потому что вместо 10 строчек можно обойтись одной.

nerezus
12.01.2007, 11:01
blaga. Нет не по этому. У него совсем неправильно.

GHostly_FOX, данные у тебя не "чистые", как ты выразился, а испорченные. Теряем информацию при твоей "обработке".

k1b0rg
12.01.2007, 11:37
int и intval() ограничены -2147483648 до 2147483648

а числа большие этому, предлагаешь уже строкой брать? тогда ты пролетишь mysql_real_escape_string тебе не поможет, взломают так что ноги согнутся...




$id=is_numeric($_GET['id'])?$_GET['id']:0;

тебя опять эта запись не устроит? )) is_numeric возьмет любое число)

nerezus
12.01.2007, 11:55
k1b0rg, спасибо, посмеялся.

А теперь немного подумай. Головой.
Предположим, в движке обрабатываем ее как:
1) ...как строку. Тогда причем int/intval() ?
2) ...как число. Тогда туда и не должны попасть такие значения, а int/intval() обрежет только неправильные.

nc.STRIEM
14.01.2007, 01:29
nerezus молодца! реальн клево отписал! я даж посмеялся! хоть не впадлу читать было, т.к. не много)))

а ваше я обычно все параметры передоваемые в запрос беру в ' ' а в самих параметрах экранирую ' и всегото!))

_Great_
14.01.2007, 01:40
а ваше я обычно все параметры передоваемые в запрос беру в ' ' а в самих параметрах экранирую ' и всегото!))
ну дык так и надо делать правильно.
mysql_escape_string поможет правильно передать любую строку в базу данных, а intval поможет передать число

nc.STRIEM
14.01.2007, 01:50
а не прощи ли сделать

$str=str_replace("'","\'",$str);

nerezus
14.01.2007, 11:51
Конечно нет.
запрос можно испортить.
А эта функция экранирует еще и другие символы.

p-range
14.01.2007, 19:32
Я уже писал в подобной теме. Зачем создавать громоздкие функции для экранирования запрещенных символов, если все уже давно придумано за нас.

вот пример безопасного кода:
<?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);
// вывод результата
}
}
?>

вот.

nerezus
14.01.2007, 23:27
Почти верно.
Почему почти?
$val = isset($_GET['val']) ? (int)$_GET['val'] : 0;

ZaCo
15.01.2007, 00:16
от инекции да. все верно.
>>но это не секурити-дырка.
бебе от инекции да, но секурити;) тк можно получить раскрытие пути. чем не бага.

_Great_
15.01.2007, 10:20
ZaCo, а если у меня еррор_репортенг по нулям? :)

nerezus
15.01.2007, 11:07
На сервере он всегда по нулям ;)
А на девелоперской тачке по максимуму ;)

nerezus
02.01.2008, 16:14
Обновил.

Meanor
08.01.2008, 00:49
У меня в голове появилась кощунственная мысль засунуть кусочек кода в скрипт с библиотекой функций/классов чтобы он проводил через себя все 3 массива куков, пост и гет. С каждым элементом он производил определенные действия , а потом засовывал их обратно в массив.

Вопрос насколько это нужно и сильно ли это нагрузит все?

Macro
08.01.2008, 00:51
У меня в голове появилась кощунственная мысль засунуть кусочек кода в скрипт с библиотекой функций/классов чтобы он проводил через себя все 3 массива куков, пост и гет. С каждым элементом он производил определенные действия , а потом засовывал их обратно в массив.

Вопрос насколько это нужно и сильно ли это нагрузит все?
что-то типа foreach($_REQUEST as $key=>$value){}

nerezus
08.01.2008, 00:57
Вопрос насколько это нужно и сильно ли это нагрузит все? Это абсолютно не нужно. Второй вопрос тебя не должен волновать.

Meanor
08.01.2008, 01:09
что-то типа foreach($_REQUEST as $key=>$value){}

Скрипт составить не проблема, вопрос в том, нужно ли это делать, т.е. предпочтительней "мыть" входящие данные на входе по-отдельности или все сразу. Исходя из вышестоящего поста можно стелать вывод, что путь наибольшей головной боли предпочтительней ;)

nerezus
08.01.2008, 01:18
Какой нафиг головной боли? Делай, как я написал, и ее не будет совсем. Нахрен тебе портить данные?

Isis
08.01.2008, 03:59
Была бы статья о всех методах защиты....был бы большой плюс

FraiDex
02.02.2008, 01:09
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
Ну вот, я кратко описал способы решения данной проблемы. Если вам есть что добавить, просьба отписать в эту тему. Всем удачи.

DIAgen
02.02.2008, 01:14
FraiDex
НИЧЕГО фильтровать не надо. СУБД - на то она и СУБД, а не херня какая-то, чтобы нормально любые данные принимать.

FraiDex
02.02.2008, 01:17
фаг.. но ведь вё равно принимает. спецсимволы она не фильтрует

DIAgen
02.02.2008, 01:31
фаг.. но ведь вё равно принимает. спецсимволы она не фильтрует
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;
}

Isis
26.02.2008, 03:17
Достаточно прогонять текстовые переменные по даной функции и больше не чего не надо
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

neval
14.04.2008, 22:58
На вид большая функция а =\\

1) Зачем цифры переводить через эту функцию?
Достаточно
<?php
$xek = intval($xek);
?>




зри в корень )

Сообщение от DIAgen

Достаточно прогонять текстовые переменные по даной функции и больше не чего не надо

nerezus
02.10.2008, 17:10
Могу скинуть свою обертку для запросов. Нужно?
На самом деле это боян, обертка типа.

PEHAT
16.11.2008, 19:57
...
$val = (int)$_GET['val'];
$val = mysql_escape_string($val);
....

А зачем число ещё и mysql_escape_string'ом обрабатывать?

Krist_ALL
04.09.2009, 20:19
Mysql_real_escape_string не спасет от слепых инекций.

.Slip
04.09.2009, 20:21
Mysql_real_escape_string не спасет от слепых инекций.
А не от слепых спасает?:о

aleksej_sumarok
19.09.2009, 13:39
Могу скинуть свою обертку для запросов. Нужно?
На самом деле это боян, обертка типа.

Если не трудно скинь пожалуйста :)

Pashkela
27.09.2009, 21:59
в топике ничего не упомянуто об:

1. реферере
2. сессии
3. прочие "особые" моменты

))

Практически никто этого не обрабатывает, если говорить про фул_паф_дискложен

nerezus
28.09.2009, 00:58
Pashkela, ну я думал, что понятно, что нельзя доверять любому вводу )

Если не трудно скинь пожалуйста Его уже не осталось, да и не нужен он - это было слабое подобие Zend_Db

m0Hze
28.09.2009, 02:08
Pashkela, ну я думал, что понятно, что нельзя доверять любому вводу )

Его уже не осталось, да и не нужен он - это было слабое подобие Zend_Db
Кстати,если уж дело зашло до Zend_Db, добавлю от себя отличный мануал по этой "обертке".
http://docs.huihoo.com/php/zend/ZendFramework-0.1.5/documentation/end-user/ru/zend.db.html
Читать очень легко,нет никаких супер-слов,все коды комментируються.В общем осваивайте,я сам остановился именно на Zend_Db.

nerezus
28.09.2009, 07:27
Кстати,если уж дело зашло до 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 на оффсайте?)))

m0Hze
28.09.2009, 12:40
Чем же мануал по 0.1.5 версии актуальнее актуального 1.9.x на оффсайте?)))
Тем,что он короче,и понятнее)
Хотя,кому как,лично мне в свое время было проще прочитать тот ман,чем офф :) Ибо много еще не понимал

Explоit
28.09.2009, 12:43
Статья про анти sql-inj, а ачат - анти хак сайт,

а и ещё осталось не писать сплоиты, а исправлять баги веб приложений

Gray_Wolf
28.09.2009, 13:02
Статья про анти sql-inj, а ачат - анти хак сайт,

а и ещё осталось не писать сплоиты, а исправлять баги веб приложений
Вообщето ачат это сайт по аудиту безопасности.
Так что всё верно...

Forcer
23.10.2009, 03:16
Ничего не сказано про prepared statement'ы. Именно из-за их использования ORM движки обладают побочным эффектом защиты от sql-inj.

nerezus
23.10.2009, 10:20
Ничего не сказано про prepared statement'ы. Именно из-за их использования ORM движки обладают побочным эффектом защиты от sql-inj. Ну это личные внутренности ОРМ, он может и по типу эскейпить просто. ;)
НО про них надо в другом месте сказать, обновлю )

Gray_Demon
12.11.2009, 06:46
Уже на многих ру хостах юнион селект рубают , надежда ток на кавычку и знание движка(((

nerezus
12.11.2009, 11:07
Уже на многих ру хостах юнион селект рубают Не верю. Если и есть такие, то это единичные случаи за "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
много чего можно добавить к этому коду, но сам подход..?

Qwazar
18.12.2009, 18:23
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
спасибо, теперь разобрался

wolmer
18.12.2009, 18:50
при SQL проскочит любой твой отфильтрованный контент в разном регистре UnIoN
Не соглашусь, сейчас пробывал в опере 10 набрать в get параметре это => "SeLEcT" (без ковычек), итог => не проскочило слово

Вообще да, плохая защита

cr0w
18.12.2009, 19:17
что думаете про такой подход?

Это ппц.
Засунуть в коммент в скл-инъекции знак "?" - вот и весь обход "фильтрации":
?lala=-1+/*?*/union+select+...
(;

Nightmarе

Буква "i" в той регулярке - модификатор...

phpdreamer
18.12.2009, 20:05
Это ппц.
Засунуть в коммент в скл-инъекции знак "?" - вот и весь обход "фильтрации":
?lala=-1+/*?*/union+select+...
(;

Nightmarе

Буква "i" в той регулярке - модификатор...
я тоже сразу подумал что надо проверять еще count массива... вопрос был не о том, но больше вопросов нет =)

imy681
19.12.2009, 13:15
Скули обречены на вымирание :)
Юзайте mysqli и ничего фильтровать не надо и искейпить тоже не надо ничего.

$mysqli = new mysqli();
$mysqli->prepare("select * from data where id = ?");

и далее по тексту :)

Seravin
13.02.2010, 05:03
А если так использовать можно избежать 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;
}

Так вроде и раскрытия путей не будет

b3
13.02.2010, 05:58
А где проверка на то что $par может быть массив?

nerezus
13.02.2010, 11:06
А если так использовать можно избежать xss/sqli??? Самый говнокодистый говнокод в этой теме.

Seravin
17.02.2010, 00:36
Самый говнокодистый говнокод в этой теме.
На самом деле это не просто самый говнокодистый говнокод, это код который не работает и не имеет смысла!
И это меня заставило подумать о том что писал 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
}
?>

Gifts
04.04.2010, 01:28
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(); ?>

Думаю есть ещё варианты, но копать лень. Это самое очевидное.

Тебе правильно сказали, завязывай с фильтрацией, сила не в ней, а в правильной обработке переменных.

Всего не учтёшь, как видишь

o4zloy
26.05.2010, 12:06
Насчет полной фильтрации всего, то это хрень, согласен с 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.");

Failure
26.05.2010, 12:21
просто заворачивая в хеш принятые от юзера логин\пароль
круто, действительно очень очень круто
давай тогда сразу

<?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;

чуть-чуть бред да?

o4zloy
26.05.2010, 12:46
А юзание фильтра запросов на 8кг разве не влияет на оптимизацию? Причем при каждом селекте, инсерте, апдейте...

К тому же это была именно аутентификация, а не юзание всего и вся.

Ну я, вроде бы, написал что тема раскрыта, если её внимательно почитать то написано что фильтровать не надо, и фильтров "по 8кг" быть не должно

Если внимательно почитать мой пост, то там написано что хеш используется именно в том случае, но вам это не помешало мягко гря "потроллить".

Тема касается анти sql-inj, но если продолжаем то...
Оффтоп:
$old_login = substr($hash,0,32);
$old_pass = substr($hash,32);
$hash = md5($new_login).md5($new_pass);

Gifts
26.05.2010, 14:02
o4zloy два запроса вместо одного, и следует напомнить, что md5 не самый быстрый алгоритм

Смысл темы не в том, чтобы защитить данное конкретное обращение к БД (да, мд5 от введенных данных будет работать). А чтобы приучить к правильному подходу к работе с СУБД в целом. Вместо того чтобы выдумывать костыль под каждый запрос, нужно просто правильно обрабатывать данные

o4zloy
26.05.2010, 15:32
o4zloy два запроса вместо одного, и следует напомнить, что md5 не самый быстрый алгоритм

Почему два?
Если, в базе находим этот хеш, значит юзер прошел проверку логина\пароля.
Насчет быстродействия, при входе на ресурс, все равно идет проверка пароля, и используют хеширование(двойное, а иногда и тройное) или это не так?)
Почему бы не совместить, с пользой для дела, полностью исключив при этом потенциальную дыру(в случае отсутствия защиты).

Смысл темы не в том, чтобы защитить данное конкретное обращение к БД.
А чтобы приучить к правильному подходу к работе с СУБД в целом.

Ммм...в целом? Тема вряд ли осилит такие масштабы, не на один том получится.
По моему, тема посвящена формированию правильной выборки из бд без возможности нарушения запроса неверными данными от юзера.

Конкретный пример, был приведен как вариант полного исключения нарушения запроса, он не претендует на лавры образцово-показательного, и уж тем более как шаблон всех запросов к бд.