[help] Фильтрация GET данных

Статус
В этой теме нельзя размещать новые ответы.

HatoL

Профессор
Регистрация
5 Фев 2008
Сообщения
206
Реакции
36
Собственно вопрос, как нужно фильтровать данные, переданные методом GET ? У меня в сценарии пользователь должен передавать только одну переменную, которая будет использоваться в трех случаях:

1) Отображаться в заголовке страницы (т.е. между тегами <title> и </title>)

2) Отображаться на самой странице

3) По значению переданного параметра будет происходить выборка данных из MySQL

Теперь конкретные вопросы:

1) Правильно, что в 1-ом и во 2-ом случае достаточно только удалить символы < и > ? Ведь остальные символы не могут повлиять на содержимое...

2) Что фильтровать в третьем случае ? Данные у меня могут содержать достаточно большое количество специальных символов (вот моя регулярка: [^0-9a-zA-Z_~!@^()-[{]}|.] (все спец. символы я заменил на шестнадцатиричные последовательности вида \x1F, здесь выложил так, чтобы проще разобрать было)). Если нету четкого ответа на этот вопрос, то тогда хотелось бы узнать все служебные символы в MySQL и как их заменить, чтобы они не воспринимались как служебные.

Извиняюсь, что создал кучу разных тем, просто так получилось, что сейчас начал писать свои первые скрипты (раньше только писал мелкие вещи а-ля линейный вывод данных). Тогда задам сразу еще несколько вопросов:

1) Почему, когда передаешь одинарную (') или двойную (") кавычку, то браузер отображает ее как \' или \" ? Причем когда фильтруешь ее регуляркой, слэш остается.

2) Читал в одной книге, что если передавать все данные в SQL-запросе в кавычках (т.е. вместо WHERE $id = 1 передавать WHERE $id = '1'), то взлом осуществить сложнее и впринципе с этим сложно не согласиться, т.к. таким образом мы защищаемся от передачи служебных символов SQL, т.к. они будут заключены в кавычках и воспримуться как обычные символы. Но как такое осуществить в PHP ? Преобразованием типов ?
 
Мне кажется, ты слишком пытаешься всё усложнить. Я бы передавал ГЕТом простой цифровой параметр, который мог бы принимать фиксированные значения, в таком случае нет необходимости ничего фильтровать и проверять. Где-нибудь, например, в базе или текстовом файле можно установить соответствие передаваемых вариантов параметра и значений, которые передаются в твои функции...
 
1. имхо правильнее использовать strip_tags
2. вообще это очень плохо открытым способом передавать спец-символы, необходимые в работе.
3. скорее всего дело в "magic quotes", посмотрите в php.ini
4. совершенно верное утверждение. Да и к примеру enum чисел не сработает без кавычек. Т.е. полезно выработать у себя такую привычку - брать все значения в кавычки.

а вообще:
если ожидаемое значение число - то intval (или floatval), хотя быстрее работает
PHP:
$v = (int)$_GET['v'];
А если текст - то и работать с ним как с текстом.
 
1)Выключи php-опцию magic_quotes_gpc

Добавлено через 17 минут
Скажем так, если написать что-то типа
PHP:
$id= $_GET['id'];
$query= "... WHERE id = $id";

и $id передано не будет, то возникнет ошибка SQL, потому что $query = "... WHERE id = "; и ещё кстати PHP-warning
но написав
PHP:
$id= $_GET['id'];
$query= "... WHERE id = '$id'";
после подстановки выйдет запрос $query= "... WHERE id = ''"; в котором тоже не много смысла

поэтому нужно делать
PHP:
$id= intval($_GET['id']);
$query= "... WHERE id = '$id'";

или как написал zaartix, преобразование к int. Но в этом случае переменная что будет передана, что нет, результат одинаковый с точки зрения SQL: либо $query= "... WHERE id = '0'"; либо $query= "... WHERE id = 0";
Получается что кавычки в sql-запросе спасают лишь от небрежного программирования.
 
Ребятки, я чет не понимаю... Т.е. заключение значений в SQL-запросе в кавычки не позволяет спастись от служебного значения спец-символов?

Так что мне делать, если переменная может содержать следующие значения: _~!@^()-[{]}|.. Если это выводится в заголовке, а потом на странице, то для этих случаев эти символы безопасны ? Ведь на странице по идее опасными могут быть только теги < и >, которые к тому же можно заменить &-последовательностями. Ведь так? А как быть с SQL-запросами ? Ведь такие символы вполне могут привести к хаку... Про кавычки я тоже ничего не понял...

Мне кажется, ты слишком пытаешься всё усложнить. Я бы передавал ГЕТом простой цифровой параметр, который мог бы принимать фиксированные значения, в таком случае нет необходимости ничего фильтровать и проверять. Где-нибудь, например, в базе или текстовом файле можно установить соответствие передаваемых вариантов параметра и значений, которые передаются в твои функции...
не получается так. Скрипт рассчитан на других пользователей, долго им придется узнавать где-нибудь свой ид (который к тому же хранится только в базе), чтобы залезть на свою страницу.
 
Ребятки, я чет не понимаю... Т.е. заключение значений в SQL-запросе в кавычки не позволяет спастись от служебного значения спец-символов?

Этого недостаточно. Кавычки вообще служат просто для выделения СТРОКОВЫХ значений (не числовых). Но опасные данные и возможные SQL-иньекции пропускают.

Об SQL-иньекциях я думаю есть много другой объёмной информации, но в двух словах в чём опасность:

Допустим Вы приняли переменную $id и делаете SQL-запрос:

PHP:
$sql = "SELECT * FROM tablename WHERE id = '$id'";

Например, кто-то присвоил переменной $id (которая берётся извне) такое значение:

Код:
' OR 'ok'='ok

В результате общий запрос приобретёт такой вид:

PHP:
SELECT * FROM tablename WHERE id = '' OR 'ok'='ok'

То есть как Вы видите сами по себе кавычки не спасли от опасного кода.

Хорошо, если Вы вначале регулярными выражениями прочистили $id, но если вдруг в какой-то момент забыли - то как видите опасно передавать переменную даже в такой "безобидный" запрос WHERE.

Для этого используется правильное экранирование. Я лично юзаю такую функцию:

PHP:
    /**
    * sqlQuote () - функция безопасности
    * $value - строка для обработки
    * Закавычивает опасные данные для SQL-запроса
    */
    function sqlQuote ($value)
    {
        // если magic_quotes_gpc включена - используем stripslashes
        if (get_magic_quotes_gpc())
        {
            $value = stripSlashes($value);
        }
        // Если переменная - число, то экранировать её не нужно
        // если нет - то окружем её кавычками, и экранируем
                if (!is_Numeric($value)) {
            $value = "'" . mysql_real_escape_string($value) . "'";
        }
        return $value;
    }

Она чем уникальна, что нормально работает как со строками, так и с числами (т.е. это то о чём говорил corehardcoder, что '0' и 0 не одно и тоже).

Как её использовать?

Очень просто. Просто возьмите за правило, что каждый раз когда выполняете ЛЮБОЙ SQL-запрос, в который подставляется ЛЮБАЯ переменная - обрабатывать её предварительно такой функцией.

Например:

PHP:
$sql = "SELECT * FROM tablename WHERE id = " . sqlQuote ($id);

И больше не нужно переживать за кавычки.

Даже не обязательно теперь для запросов WHERE (которые не изменяют данных) переменную обрабатывать регулярными выражениями.

Ну а для таких как INSERT, UPDATE - там уже желательно, чтобы не заполнять базу мусором. ;)

P.S. Что касается данных, которые выводятся в HTML-код, то в одном из Ваших постов указали также функцию для очистки от XSS-атак, подумайте также об её использовании если нужно (т.е. помимо регулярных выражений).

Для просмотра ссылки Войди или Зарегистрируйся
 
System777 а если использовать мой случай (т.е. заключать значения переменных в кавычки) и при этом фильтровать саму переменную на наличие такой кавычки, то ведь тогда Ваш код (' OR 'ok'='ok) не сработает, т.к. запрос примет такой вид SELECT * FROM tablename WHERE id = ' OR ok=ok'.

За функцию экранирования спасибо

Добавлено через 46 секунд
сразу вопрос: а как тогда передать в SQL-запрос кавычку ? Не как служебный символ, а как значение
 
System777 а если использовать мой случай (т.е. заключать значения переменных в кавычки) и при этом фильтровать саму переменную на наличие такой кавычки, то ведь тогда Ваш код (' OR 'ok'='ok) не сработает, т.к. запрос примет такой вид SELECT * FROM tablename WHERE id = ' OR ok=ok'

Да, в Вашем именно случае так тоже можно. Но только убедитесь что Ваше регулярное выражение хорошо фильтрует и работает.

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

Или тот же пример с неинициализированной по ошибке переменной. Я имею ввиду что для гарантии использование sqlQoute желателен (т.е. его можно использовать и после обычной проверки).

Тем более не нужно ставить кавычки там где числовой аргумент передаётся в SQL-запрос.

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

сразу вопрос: а как тогда передать в SQL-запрос кавычку ? Не как служебный символ, а как значение

В виде \' - (функция sqlQuote как раз по такому же принципу и заменяет опасные символы на обычные кавычки, которые будут уже браться как текст, то есть добавляет слеши)
 
Хм, я сейчас протестировал одну вещь. Получается, что если в строковом значении изначально используются одинарные кавыки (например echo 'aaa'), то двойные будут восприниматься как обычный символ (например можно ввести echo '"aaa"', в результате выведется "aaa" (вместе с кавычками)). А если изначально используются двойные, то наоборот. Так? Начал тестировать, потому что столкнулся с проблемой, при которой SQL-запрос сравнивал значение `id` с константой, а не переменной (я предпочитаю использовать константы, если значение не меняется). В результате запрос
Код:
'SELECT `anycolumn` FROM `tablename` WHERE `id` = ' . ID_OF_USER
где ID_OF_USER - моя константа, не сработал. Что делать в таком случае? Пробовал
Код:
'SELECT `anycolumn` FROM `tablename` WHERE `id` = ' . '\'' . ID_OF_USER . '\''
Оно то работает, только такой код тяжело читается. Есть другие варианты?
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху