Защита от SQL-enjection

Discussion in 'PHP' started by je0n, 3 Jan 2007.

  1. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    Короче нужна такая функция, которай я передаю переменную, а она ее обрабатывает и делает безопасной от 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; ). Это на тот случай если выходить не прийдеться, а еще и юзать дальше эту переменную. Ведь я не знаю как дальше будет развиваться все остальное, ради чего я и пишу этот скрипт.
    Я фигово разбираюсь во всех атаках, поэтому прошу добавить/исправить код, чтобы он был неуязвим )) даже в том случае, если эту переменну прийдеться использовать дальше как в БД, так и выводить в страницу.
     
  2. Termin@L

    Termin@L Elder - Старейшина

    Joined:
    7 Dec 2006
    Messages:
    183
    Likes Received:
    43
    Reputations:
    53
    ИМХО Проще не замарачиваться, а пользоваться функциями ereg() и htmlspecialchars(), проще явно указать - что можно, а не то что нельзя использовать, а в твоём случае пройдёт такой запрос -
    Code:
    union select 1,2,3,4,5#
    от xss тоже не спасёт, лишь осложнит задачу немного.
    Code:
     if(!ereg("[A-Za-z]{1,8}",$name)
    return false;
     
    1 person likes this.
  3. max_pain89

    max_pain89 Eat `em UP!

    Joined:
    11 Dec 2004
    Messages:
    451
    Likes Received:
    140
    Reputations:
    146
    да сопри из любого форума или КМС, так есть такие функции, просто иногда забывают их применять к переменным
     
  4. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    спасибо, решил использовать вместо strpos функцию ereg, а вместо str_replace ereg_replace. Тока недоганю как составить правильный шаблон для функций ereg. Помогите плз, чтобы он пропул русские, английские буквы, точку, запятую и цифры. Как должен выглядеть шаблон

    Меньше всего хочеться копаться в исходниках форума ;). Я уже думал об этом. Кроме того, вряд ли там все ограничивается одной функцией )
     
    #4 je0n, 3 Jan 2007
    Last edited: 3 Jan 2007
  5. gemaglabin

    gemaglabin Green member

    Joined:
    1 Aug 2006
    Messages:
    772
    Likes Received:
    842
    Reputations:
    1,369
    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;
    }
    
     
  6. Termin@L

    Termin@L Elder - Старейшина

    Joined:
    7 Dec 2006
    Messages:
    183
    Likes Received:
    43
    Reputations:
    53
    Code:
    if(!ereg("[А-Яа-яa-zA-Z0-9]{1,8}",$_POST['post'])){echo "Error";exit;}
    примерно так
     
  7. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    2Гема
    и что это?
    Эта функция очень далека от того, что надо мне?
     
  8. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    а точка, запятая, дефис,ничжнее подчеркивание (ну и все нормальные символы, включены сюда?
     
  9. Termin@L

    Termin@L Elder - Старейшина

    Joined:
    7 Dec 2006
    Messages:
    183
    Likes Received:
    43
    Reputations:
    53
    Нет тут, только - точка, запятая, кавычка, всё остальное добавляешь в квадратные скобки подряд, только дефис нужно обязательно в конец.
    P.s. пробел тоже надо вставлять
    сори не ту строку те кинул вот -
    if(!ereg("[А-Яа-яa-zA-Z0-9',.; -]{1,8}",$_POST['post'])){echo "Error";exit;}
     
    #9 Termin@L, 3 Jan 2007
    Last edited: 3 Jan 2007
    1 person likes this.
  10. DIAgen

    DIAgen Banned Life!

    Joined:
    2 May 2006
    Messages:
    1,055
    Likes Received:
    376
    Reputations:
    460
    Зачем изобретать велосипед, возми DLE 5.2 там все хорошо сделано с точки безопасносит и грамотно написано
     
  11. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    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;
    }
    
     
    #11 je0n, 3 Jan 2007
    Last edited: 3 Jan 2007
  12. darky

    darky ♠ ♦ ♣ ♥

    Joined:
    18 May 2006
    Messages:
    1,773
    Likes Received:
    825
    Reputations:
    1,418
    Зако писал антихак систему ) в принципе чуток доработать под сеья и норм
     
  13. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    Короче вот что получилось. Прошу сказать, возможен ли обход, если да, то что надо поправить, чтобы все было пучком?
    Code:
    function filter(&$value)
    {
      $b=FALSE;
      if(ereg("([;/'<>])|(union)",$value))
      {
        $value=ereg_replace("([;/'<>])|(union)","",$value);
        $b=TRUE;
      }
      return $b;
    }
    
     
  14. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    Читаю ваши куски и думаю: то ли я совасем дурак, то ли вы:
    не легче ли просто нормально добавлять запись в базу? И ВСЕ!

    Нахер вырезать из запроса какие-то символы? Нахер проверять запрос?
    СУБД - она на то и СУБД, что может принять все данные, причем делать это правильно.

    Наша задача - просто правильно их ей передать.
     
  15. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    Да, обход возможен. Возможна sql-inj в целочисленном параметре скрипта, где не требуется кавычка для выхода за пределы значения в запрос.
     
  16. Slon

    Slon Elder - Старейшина

    Joined:
    9 Dec 2005
    Messages:
    123
    Likes Received:
    21
    Reputations:
    3
    Имхо самая простая защита от sql это
    PHP:
    settype($id,integer);
    Если переменная строковая, то просто убрать все виды кавычек.

    От XSS думаю htmlspecialchars(); спасет, хотя иногда лучьше ereg()
     
    1 person likes this.
  17. p-range

    p-range Elder - Старейшина

    Joined:
    5 Feb 2006
    Messages:
    137
    Likes Received:
    145
    Reputations:
    118
    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);
    	// вывод результата
    }
    }
    ?>
    Вроде все понятно.
     
  18. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    Ага понятно... Понятно, что я гнал пытаюсь защититься от XSS и SQL-enj в одной функции ;)
     
  19. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    Ты просто не понимаешь, как работает БД ;)
     
  20. GHostly_FOX

    GHostly_FOX Elder - Старейшина

    Joined:
    4 Jan 2007
    Messages:
    34
    Likes Received:
    15
    Reputations:
    0
    Вот мой способ предотвратить какие либо попытки SQL injection или XSS

    PHP:
    function var_chek($var,$col){
        
    $var    =    substr($var0$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 инжекцию то 
    данные будут записаны в базу просто как такст!*/
     
Loading...
Similar Threads - Защита enjection
  1. GAiN
    Replies:
    3
    Views:
    7,895