Короче нужна такая функция, которай я передаю переменную, а она ее обрабатывает и делает безопасной от XSS и SQL-enjection. Функция должна изменять переменную в своем теле (по ссылке), и если переменная была опасна вернуть TRUE иначе FALSE. Вот что получилось у меня: Code: <?php function filter(&$value) { $b=FALSE; if(strpos($value,"'")) { $value=str_replace("'","",$value); $b=TRUE; } if(strpos($value,";")) { $value=str_replace(";","",$value); $b=TRUE; } if(strpos($value,"/")) { $value=str_replace("/","",$value); $b=TRUE; } if(strpos($value,"<")) { $value=str_replace("<","",$value); $b=TRUE; } if(strpos($value,">")) { $value=str_replace(">","",$value); $b=TRUE; } return $b; } ?> Ну а юзать эту функцию премерно вот так: Code: $name=$_POST["name"]; if(filter($name)) {echo "you cant use symbols ',/ here";exit;} Тока не говорите нафига изменять переменную, если все равно выхожу из скрипта (exit; ). Это на тот случай если выходить не прийдеться, а еще и юзать дальше эту переменную. Ведь я не знаю как дальше будет развиваться все остальное, ради чего я и пишу этот скрипт. Я фигово разбираюсь во всех атаках, поэтому прошу добавить/исправить код, чтобы он был неуязвим )) даже в том случае, если эту переменну прийдеться использовать дальше как в БД, так и выводить в страницу.
ИМХО Проще не замарачиваться, а пользоваться функциями ereg() и htmlspecialchars(), проще явно указать - что можно, а не то что нельзя использовать, а в твоём случае пройдёт такой запрос - Code: union select 1,2,3,4,5# от xss тоже не спасёт, лишь осложнит задачу немного. Code: if(!ereg("[A-Za-z]{1,8}",$name) return false;
да сопри из любого форума или КМС, так есть такие функции, просто иногда забывают их применять к переменным
спасибо, решил использовать вместо strpos функцию ereg, а вместо str_replace ereg_replace. Тока недоганю как составить правильный шаблон для функций ereg. Помогите плз, чтобы он пропул русские, английские буквы, точку, запятую и цифры. Как должен выглядеть шаблон Меньше всего хочеться копаться в исходниках форума . Я уже думал об этом. Кроме того, вряд ли там все ограничивается одной функцией )
Simple Machine Forums Code: function db_query($db_string, $file, $line) { global $db_cache, $db_count, $db_connection, $db_show_debug, $modSettings; // One more query.... $db_count = !isset($db_count) ? 1 : $db_count + 1; // Debugging. if (isset($db_show_debug) && $db_show_debug === true) { // Initialize $db_cache if not already initialized. if (!isset($db_cache)) $db_cache = array(); if (!empty($_SESSION['debug_redirect'])) { $db_cache = array_merge($_SESSION['debug_redirect'], $db_cache); $db_count = count($db_cache) + 1; $_SESSION['debug_redirect'] = array(); } $db_cache[$db_count]['q'] = $db_string; $db_cache[$db_count]['f'] = $file; $db_cache[$db_count]['l'] = $line; $st = microtime(); } // First, we clean strings out of the query, reduce whitespace, lowercase, and trim - so we can check it over. if (empty($modSettings['disableQueryCheck'])) { $clean = ''; $old_pos = 0; $pos = -1; while (true) { $pos = strpos($db_string, '\'', $pos + 1); if ($pos === false) break; $clean .= substr($db_string, $old_pos, $pos - $old_pos); while (true) { $pos1 = strpos($db_string, '\'', $pos + 1); $pos2 = strpos($db_string, '\\', $pos + 1); if ($pos1 === false) break; elseif ($pos2 == false || $pos2 > $pos1) { $pos = $pos1; break; } $pos = $pos2 + 1; } $clean .= '%s'; $old_pos = $pos + 1; } $clean .= substr($db_string, $old_pos); $clean = trim(strtolower(preg_replace(array('~\s+~s', '~/\*!40001 SQL_NO_CACHE \*/~', '~/\*!40000 USE INDEX \([A-Za-z\_]+?\) \*/~'), array(' ', '', ''), $clean))); // We don't use UNION in SMF, at least so far. But it's useful for injections. if (strpos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0) $fail = true; // Comments? We don't use comments in our queries, we leave 'em outside! elseif (strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, ';') !== false) $fail = true; // Trying to change passwords, slow us down, or something? elseif (strpos($clean, 'set password') !== false && preg_match('~(^|[^a-z])set password($|[^[a-z])~s', $clean) != 0) $fail = true; elseif (strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0) $fail = true; // Sub selects? We don't use those either. elseif (preg_match('~\([^)]*?select~s', $clean) != 0) $fail = true; if (!empty($fail)) { log_error('Hacking attempt...' . "\n" . $db_string, $file, $line); fatal_error('Hacking attempt...', false); } } $ret = mysql_query($db_string, $db_connection); if ($ret === false && $file !== false) $ret = db_error($db_string, $file, $line); // Debugging. if (isset($db_show_debug) && $db_show_debug === true) $db_cache[$db_count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st)); return $ret; }
Нет тут, только - точка, запятая, кавычка, всё остальное добавляешь в квадратные скобки подряд, только дефис нужно обязательно в конец. P.s. пробел тоже надо вставлять сори не ту строку те кинул вот - if(!ereg("[А-Яа-яa-zA-Z0-9',.; -]{1,8}",$_POST['post'])){echo "Error";exit;}
Зачем изобретать велосипед, возми DLE 5.2 там все хорошо сделано с точки безопасносит и грамотно написано
2Termin@L Спасибо братик. А как юзать ereg_replace, чтобы заменить все опасные символы на "". Типа так: Code: if(!ereg("[А-Яа-яa-zA-Z0-9]{1,8}",$value)) { $value=ereg_replace("[А-Яа-яa-zA-Z0-9]{1,8}","",$value) } или нет? Что-то вот так, не заменяется символы в строке Code: function filter(&$value) { $b=FALSE; if(!ereg('[А-Яа-яa-zA-Z0-9,._"-]{1,8}',$value)) { $value=ereg_replace('[А-Яа-яa-zA-Z0-9,._"-]{1,8}','',$value); $b=TRUE; } return $b; }
Короче вот что получилось. Прошу сказать, возможен ли обход, если да, то что надо поправить, чтобы все было пучком? Code: function filter(&$value) { $b=FALSE; if(ereg("([;/'<>])|(union)",$value)) { $value=ereg_replace("([;/'<>])|(union)","",$value); $b=TRUE; } return $b; }
Читаю ваши куски и думаю: то ли я совасем дурак, то ли вы: не легче ли просто нормально добавлять запись в базу? И ВСЕ! Нахер вырезать из запроса какие-то символы? Нахер проверять запрос? СУБД - она на то и СУБД, что может принять все данные, причем делать это правильно. Наша задача - просто правильно их ей передать.
Да, обход возможен. Возможна sql-inj в целочисленном параметре скрипта, где не требуется кавычка для выхода за пределы значения в запрос.
Имхо самая простая защита от sql это PHP: settype($id,integer); Если переменная строковая, то просто убрать все виды кавычек. От XSS думаю htmlspecialchars(); спасет, хотя иногда лучьше ereg()
Code: <?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); // вывод результата } } ?> Вроде все понятно.
Вот мой способ предотвратить какие либо попытки SQL injection или XSS PHP: 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; } $var=var_chek($_GET['var'],4); Если значение $var это просто передаваемый индекс для выборки из базы то достаточно его обрезать до 4-х символов, в 4 символа точно ничего не впишешь... А если идет запись данных в базу то вот пример работы скрипта: PHP: /*В переменную VAR передадим код ну к примеру такой - "><script>alert()</script>*/ $var=$_GET['var']; mysql_query("INSERT INTO base SET text='".var_chek($var)."'"); /*И в базу уйдут такие данные - script alert script , И даже если будете передавать SQL инжекцию то данные будут записаны в базу просто как такст!*/