Web

Проблемы при использовании $_REQUEST[]

Я читал в руководстве о том, что не следует использовать переменную $_REQUEST. Обычно я этого не делаю, но иногда это удобно. Что в этом плохого?

 

Ответ 1

Нет абсолютно ничего плохого в том, чтобы принимать входные данные из $_GET и $_POST комбинированным способом. На самом деле, это то, что вы почти всегда хотите сделать:

  1. Для обычного идемпотентного запроса, обычно отправляемого через GET, есть вероятность, что объем данных, который вам нужен, не поместится в URL, поэтому с практической точки зрения он должен быть преобразован в POST-запрос.

  2. Для запроса, который имеет реальный эффект, вы должны проверить, что он отправлен методом POST. Но способ сделать это проверить $_SERVER['REQUEST_METHOD'] явно, а не полагаться на то, что $_POST пуст для GET. И в любом случае, если метод POST, вы все равно захотите убрать некоторые параметры запроса из URL.

Проблема с $_REQUEST не связана со совмещением параметров GET и POST. Дело в том, что по умолчанию они также включают $_COOKIE. А куки совсем не похожи на параметры отправки формы: вы почти никогда не захотите рассматривать их как одно и то же.

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

Вы можете изменить это поведение на гораздо более разумный порядок GP (без C) с помощью конфигурации request_order в PHP 5.3. Там, где это невозможно, я лично избегаю $_REQUEST и, если мне нужен комбинированный массив GET+POST, создаю его вручную.

 

Ответ 2

Я разбирался в некоторых сообщениях новостной группы по PHP Internals и нашел интересную дискуссию на эту тему. Первоначальная тема была о чем-то другом, но замечание Стефана Эссера, эксперта по безопасности в мире PHP (если не самого лучшего эксперта), повернуло дискуссию в сторону последствий использования $_REQUEST для безопасности на несколько сообщений.

 $_REQUEST является одним из самых больших недостатков дизайна в PHP. Каждое приложение, использующее $_REQUEST, скорее всего, уязвимо к проблемам отложенной подделки межсайтовых запросов (это означает, что если, например, существует cookie с именем (age), то оно всегда будет перезаписывать содержимое GET/POST, и поэтому будут выполняться нежелательные запросы).

  1. Дело не в том, что кто-то может подделать переменные GET, POST; COOKIE. И в этом случае COOKIE будут перезаписывать данные GET и POST в REQUEST.

  2. Поэтому я могу заразить ваш браузер кукой, в которой, например, написано: action=logout, и с этого дня вы больше не сможете пользоваться приложением, потому что REQUEST[action] будет logout навсегда (пока вы вручную не удалите куку).

  3. А заразить вас с помощью COOKIE так просто...

             a) Я могу использовать XSS-атаку в любом приложении на поддомене.

             б) Вы когда-нибудь пробовали установить cookie для *.co.uk или *.co.kr, когда у вас там один домен?

             c) Другие междоменные способы…

        4. И если вы считаете, что это не проблема, тогда я могу сказать вам, что есть простая возможность установить, например, куки *.co.kr, что приводит к тому, что несколько версий PHP просто возвращают белые страницы. Представьте себе: всего                один куки, чтобы разрушить все PHP-страницы в *.co.kr.

        5. А установив в переменной +PHPSESSID=illegal нелегальный ID сессии в cookie, действительной для *.co.kr, вы также сможете DOSить все PHP-приложения, использующие PHP-сессии...

Как вы видите, основная проблема с $_REQUEST заключается не столько в том, что в нем есть данные из $_GET и $_POST, но и из $_COOKIE. Некоторые люди предложили изменить порядок заполнения $_REQUEST, например, сначала заполнить его $_COOKIE, но это может привести ко множеству других потенциальных проблем, например, с обработкой сессий.

Однако вы можете полностью исключить $_COOKIES из глобального $_REQUEST, чтобы он не перезаписывался другими массивами. На самом деле, вы можете ограничить его любой комбинацией стандартного содержимого, как сказано в руководстве PHP по настройке variable_order ini:

variable_order Устанавливает порядок разбора переменных EGPCS (Environment, Get, Post, Cookie и Server). Например, если variables_order имеет значение "SP", то PHP создаст суперглобалы $_SERVER и $_POST, но не создаст $_ENV, $_GET и $_COOKIE. Установка значения "" означает, что суперглобалы не будут созданы.

Но с другой стороны, вы также можете рассмотреть возможность не использовать $_REQUEST вообще, просто потому, что в PHP вы можете получить доступ к Environment, Get, Post, Cookie и Server в их собственных глобалах и получить на один вектор атаки меньше. Вам все равно придется санитаризовать эти данные, но это уже меньшая причина для беспокойства.

Теперь вы можете задаться вопросом, почему $_REQUEST все-таки существует и почему он не удален. Этот вопрос также был задан на PHP Internals.

Чем больше подобных вещей мы удаляем, тем сложнее людям быстро перейти на новые, более быстрые и безопасные версии PHP. Это вызывает гораздо большее разочарование для всех, чем несколько "небезопасных" унаследованных функций. Если есть достойная техническая причина, производительность или безопасность, то мы должны внимательно посмотреть на нее. В данном случае нам следует обратить внимание не на то, нужно ли удалять $_REQUEST, а на то, нужно ли удалять из него данные cookie. Многие конфигурации уже делают это, включая все мои собственные, и есть веская причина для безопасности не включать куки в $_REQUEST. Большинство людей используют $_REQUEST для обозначения GET или POST, не понимая, что он также может содержать куки, и поэтому плохие парни могут потенциально сделать некоторые трюки с инъекцией куки и сломать приложения.

 

Ответ 3

$_REQUEST обычно считается вредным по той же причине, по которой простые и средние по сложности преобразования данных часто выполняются в коде приложения, а не объявляются в SQL. Таким образом, если вы склонны использовать $_REQUEST везде, я могу делать через GET все, что могу через POST, что означает установку тегов <img> на моем (вредоносном) сайте, которые заставят пользователей, вошедших в ваш модуль электронной коммерции, молча покупать товары, или я могу заставить их щелкнуть по ссылкам, которые приведут к опасным действиям или раскрытию конфиденциальной информации.

Однако это происходит из-за того, что начинающий или, по крайней мере, неопытный PHP-программист допускает простые ошибки. Во-первых, знайте, когда данные какого типа уместны. Например, у меня есть веб-сервис, который может возвращать ответы в URLEncoding, XML или JSON. Приложение решает, как отформатировать ответ, проверяя заголовок HTTP_ACCEPT, но его можно принудить к одному конкретному формату, отправив параметр format.

При проверке содержимого параметра format он может быть отправлен через querystring или postdata в зависимости от множества факторов, не последним из которых является то, хочет ли вызывающее приложение прикрутить к своему запросу "&format=json". В этом случае $_REQUEST очень удобен, поскольку избавляет меня от необходимости набирать что-то вроде этого:

$format = isset($_POST['format']) ? $_POST['format'] 

    : (isset($_GET['format']) ? $_GET['format'] : null);

 Как безопасно использовать $_REQUEST

Знайте структуру и тип своих данных. Вы должны иметь некоторое представление о том, какого рода данные вы получите, поэтому обезопасьте их соответствующим образом. Данные для базы данных? addslashes() или *_escape_string(). Собираетесь показать их пользователю? htmlentities() или htmlspecialchars(). Ожидаете числовые данные? is_numeric() или ctype_digit(). Не обращайтесь напрямую к данным суперглобалов, предоставленным пользователем. Возьмите за привычку каждый раз проводить санитарную обработку данных и перемещать их в чистые переменные, даже если это просто $post_clean. В качестве альтернативы вы можете просто очищать данные непосредственно в суперглобалах, но я выступаю за использование отдельной переменной, потому что так легче обнаружить уязвимости в коде, поскольку все, что указывает непосредственно на суперглобал, а не на его санированный эквивалент, считается опасной ошибкой.

Знайте, откуда должны поступать данные. Ссылаясь на мой пример выше, вполне разумно разрешить переменной формата ответа отправлять данные через GET или POST. Я также разрешаю отправлять переменную "действие" любым из этих методов. Однако сами действия имеют очень специфические требования к тому, какой HTTP-оператор допустим. Например, функции, которые вносят изменения в данные, используемые сервисом, могут быть отправлены только через POST. Запросы на определенные типы данных, не требующих особых или низких привилегий (например, динамически создаваемые изображения карт), могут обслуживаться в ответ на запросы любым из этих методов.

 

Ответ 4

На самом деле, мне нравится его использовать. Он дает вам возможность использовать GET или POST, что может пригодиться для таких вещей, как поисковые формы, где в большинстве случаев данные отправляются через POST, но иногда вам может потребоваться, что вы хотите дать ссылку на определенный поисковый запрос, поэтому вы можете использовать GET параметры для этого.

Кроме того, если вы посмотрите на многие другие языки (например, ASP.NET), они вообще не делают различий между GET и POST переменными.

Я никогда не использовал REQUEST для получения значений COOKIE. Это НЕ хорошая идея использовать REQUEST для получения значений COOKIE. Я считаю, что существует реальный потенциал для подделки межсайтовых запросов, если вы это сделаете.

Кроме того, порядок, в котором материал загружается в REQUEST, контролируется параметрами конфигурации в php.ini (variables_order и request_order). Таким образом, если вы передали одну и ту же переменную через POST и GET, то какая из них попадет в REQUEST, зависит от этих параметров. Это может повлиять на переносимость, если вы зависите от определенного порядка передачи параметров, а эти параметры настроены иначе, чем вы ожидаете.

 

Ответ 5

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

Может быть удобно использовать $_REQUEST, когда ваши скрипты могут одинаково отвечать как на GET, так и на POST. Однако я бы утверждал, что это крайне редкий случай, и в большинстве случаев предпочтительнее использовать две отдельные функции для обработки двух разных концепций или, по крайней мере, проверять метод и выбирать правильные переменные. Поток программы обычно намного легче отслеживать, когда не нужно перекрестно ссылаться на то, откуда могут прийти переменные. Будьте честны к человеку, которому придется поддерживать ваш код через 6 месяцев. Это можете быть вы сами.

В дополнение к проблемам безопасности и WTF, вызванным cookies и переменными окружения в переменной REQUEST, подумайте о том, что может произойти в будущем, если PHP начнет поддерживать другие методы, такие как PUT и DELETE. Хотя крайне маловероятно, что они будут объединены в суперглобальную переменную REQUEST; вполне возможно, что они могут быть включены в качестве опции в параметр variable_order. Таким образом, вы не имеете ни малейшего представления о том, что содержит REQUEST и что имеет приоритет, особенно если ваш код развернут на стороннем сервере.

Является ли POST более безопасным, чем GET? Не совсем. Лучше использовать GET там, где это целесообразно, потому что в журналах легче увидеть, как ваше приложение эксплуатируется, когда оно подвергается атаке. POST лучше использовать для операций, влияющих на состояние домена, потому что поисковые роботы обычно не следят за ними, а механизмы предсказуемой выборки не удалят весь ваш контент, когда вы войдете в свою CMS. Однако вопрос был не о достоинствах GET и POST, а о том, как получатель должен относиться к входящим данным и почему плохо их объединять, так что это действительно просто BTW.

 

Ответ 6

Я думаю, что с $_REQUEST нет проблем, но мы должны быть осторожны при его использовании, так как это набор переменных из 3 источников (GPC). Я думаю, что $_REQUEST все еще можно использовать, чтобы сделать старые программы совместимыми с новыми версиями php, но если мы начинаем новые проекты (включая новые библиотеки), я думаю, что мы не должны больше использовать $_REQUEST, чтобы сделать программы более понятными. Мы даже должны рассмотреть возможность удаления использования $_REQUEST и замены его функцией-оберткой, чтобы сделать программу проще, особенно при обработке больших отправленных текстовых данных, так как $_REQUEST содержит копии $_POST.

// удалите $_REQUEST при выполнении программы, программа станет проще

// при отправке большого текста

unset($_REQUEST);

// функция-обертка для получения запроса var

function GetRequest($key, $default = null, $source = '') {

  if ($source == 'get') {

    if (isset($_GET[$key])) { 

      return $_GET[$key]; 

    } else { 

      return $default; 

    }

  } else if ($source == 'post') {

    if (isset($_POST[$key])) { 

      return $_POST[$key]; 

    } else { 

      return $default; 

    }

  } else if ($source == 'cookie') {

    if (isset($_COOKIE[$key])) { 

      return $_COOKIE[$key]; 

    } else { 

      return $default; 

    }

  } else {

    // источник не указан, тогда найдите в GPC

    if (isset($_GET[$key])) {

      return $_GET[$key];     

    } else if (isset($_POST[$key])) {

      return $_POST[$key]; 

    } else if (isset($_COOKIE[$key])) {

      return $_COOKIE[$key]; 

    } else {

      return $default; 

    } 

  }

}

 

Схожие статьи

Web

Преобразовать разделенных двоеточиями массив ключ: значение в массив с ключами

Web

Выполнение фонового процесса в PHP

Поиск по GitHub: как найти репозитории, нужный код или разработчика?
Web

Поиск по GitHub: как найти репозитории, нужный код или разработчика?

Web

Пример использования bind_result/get_result

×