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

Тема в разделе "PHP", создана пользователем HatoL, 16 июл 2008.

Статус темы:
Закрыта.
Модераторы: latteo
  1. HatoL

    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 ? Преобразованием типов ?
     
  2. vovaNux

    vovaNux Постоялец

    Регистр.:
    10 апр 2007
    Сообщения:
    125
    Симпатии:
    16
    Мне кажется, ты слишком пытаешься всё усложнить. Я бы передавал ГЕТом простой цифровой параметр, который мог бы принимать фиксированные значения, в таком случае нет необходимости ничего фильтровать и проверять. Где-нибудь, например, в базе или текстовом файле можно установить соответствие передаваемых вариантов параметра и значений, которые передаются в твои функции...
     
  3. zaartix

    zaartix Постоялец

    Регистр.:
    15 май 2006
    Сообщения:
    73
    Симпатии:
    27
    1. имхо правильнее использовать strip_tags
    2. вообще это очень плохо открытым способом передавать спец-символы, необходимые в работе.
    3. скорее всего дело в "magic quotes", посмотрите в php.ini
    4. совершенно верное утверждение. Да и к примеру enum чисел не сработает без кавычек. Т.е. полезно выработать у себя такую привычку - брать все значения в кавычки.

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

    corehardcoder Создатель

    Регистр.:
    29 июн 2008
    Сообщения:
    20
    Симпатии:
    2
    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:
    $idintval($_GET['id']);
    $query"... WHERE id = '$id'";
    или как написал zaartix, преобразование к int. Но в этом случае переменная что будет передана, что нет, результат одинаковый с точки зрения SQL: либо $query= "... WHERE id = '0'"; либо $query= "... WHERE id = 0";
    Получается что кавычки в sql-запросе спасают лишь от небрежного программирования.
     
  5. HatoL

    HatoL

    Регистр.:
    5 фев 2008
    Сообщения:
    206
    Симпатии:
    36
    Ребятки, я чет не понимаю... Т.е. заключение значений в SQL-запросе в кавычки не позволяет спастись от служебного значения спец-символов?

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

    не получается так. Скрипт рассчитан на других пользователей, долго им придется узнавать где-нибудь свой ид (который к тому же хранится только в базе), чтобы залезть на свою страницу.
     
    zaartix нравится это.
  6. Miraage

    Miraage Angular/Laravel

    Регистр.:
    3 июн 2008
    Сообщения:
    230
    Симпатии:
    51
    я бы так не делал, т.к. если в $v будет не цифра ( в любой системе счисления), то результат будет такой:
    $v = ""
     
  7. System777

    System777 Создатель

    Регистр.:
    20 апр 2008
    Сообщения:
    30
    Симпатии:
    13
    Этого недостаточно. Кавычки вообще служат просто для выделения СТРОКОВЫХ значений (не числовых). Но опасные данные и возможные 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-атак, подумайте также об её использовании если нужно (т.е. помимо регулярных выражений).

    код этой функции
     
    HatoL нравится это.
  8. HatoL

    HatoL

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

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

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

    System777 Создатель

    Регистр.:
    20 апр 2008
    Сообщения:
    30
    Симпатии:
    13
    Да, в Вашем именно случае так тоже можно. Но только убедитесь что Ваше регулярное выражение хорошо фильтрует и работает.

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

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

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

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

    В виде \' - (функция sqlQuote как раз по такому же принципу и заменяет опасные символы на обычные кавычки, которые будут уже браться как текст, то есть добавляет слеши)
     
  10. HatoL

    HatoL

    Регистр.:
    5 фев 2008
    Сообщения:
    206
    Симпатии:
    36
    Хм, я сейчас протестировал одну вещь. Получается, что если в строковом значении изначально используются одинарные кавыки (например 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 . '\''
    Оно то работает, только такой код тяжело читается. Есть другие варианты?
     
Статус темы:
Закрыта.