Что не так с использованием $_REQUEST[]?

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

15 ответов

Решение

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

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

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

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

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

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

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

Цитирование Стефана Эссера о PHP Internals

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

и в более позднем ответе на ту же тему

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

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

И заразить тебя КУКИ так просто...
а) Я мог бы использовать XSS vuln в любом приложении на поддомене
б) Вы когда-нибудь пытались установить cookie для *.co.uk или *.co.kr, когда у вас там один домен?
в) Прочие междоменные связи какими бы то ни было способами...

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

И, установив недопустимый идентификатор сеанса в файле cookie, допустимом для *.co.kr, в переменную с именем +PHPSESSID=недопустимый, вы все равно можете DOS использовать каждое PHP-приложение в Корее, используя PHP-сессии...

Обсуждение продолжается еще для нескольких сообщений и интересно читать.


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

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

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

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


Теперь вы можете задаться вопросом, почему $_REQUEST существует и почему он не удален. Об этом также спрашивали в PHP Internals. Цитируя Расмуса Лердорфа о том, почему существует $_REQUEST? на внутреннем PHP

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

Во всяком случае, надеюсь, что это пролило свет.

$_REQUEST обычно считается вредным по той же причине, по которой преобразования кода простой-средней сложности часто выполняются в коде приложения, а не объявляются в SQL: некоторые программисты отстой.

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

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

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

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

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

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


  1. Знайте свои данные: у вас должно быть какое-то ожидание относительно того, какие данные вы получите, поэтому проведите соответствующую очистку. Данные для базы данных? addslashes() или же *_escape_string(), Собираетесь показать его обратно пользователю? htmlentities() или же htmlspecialchars(), Ожидаете числовые данные? is_numeric() или же ctype_digit(), По факту, filter_input()и связанные с ним функции предназначены только для проверки и очистки данных. Используйте эти инструменты всегда.
  2. Не обращайтесь к предоставленным пользователем данным суперглобальных напрямую. Привыкайте каждый раз очищать ваши данные и перемещать данные в чистые переменные, даже если это просто$post_clean, В качестве альтернативы, вы можете просто очистить непосредственно в суперглобалах, но я рекомендую использовать отдельную переменную, потому что это облегчает обнаружение уязвимостей в коде, посколькувсе, что указывает непосредственно на суперглобальный, а не на его очищенный эквивалент, считается опасной ошибкой.,
  3. Знайте, откуда ваши данные должны поступать. Ссылаясь на мой пример, приведенный выше, вполне разумно разрешить отправку переменной формата ответа через GET или POST. Я также разрешаю отправлять переменную "action" любым из этих методов. Однако сами действия имеют очень специфические требования в отношении того, какой HTTP-глагол приемлем. Например, функции, которые вносят изменения в данные, используемые сервисом, могут отправляться только через POST. Запросы на определенные типы данных без прав доступа или с низким уровнем привилегий (например, динамически генерируемые изображения карты) могут обслуживаться в ответ на запросы любого из методов.

В заключение запомните это простое правило:

БЕЗОПАСНОСТЬ - ЧТО ВЫ ДЕЛАЕТЕ, ЛЮДИ!

РЕДАКТИРОВАТЬ:

Я настоятельно рекомендую совет Бобинса: если можете, установите request_order параметр в php.ini в "GP"; то есть, нет компонента cookie. В 98%+ случаев практически нет рационального обоснования этого, поскольку данные cookie почти никогда не следует считать сопоставимыми со строкой запроса или постданными.

PS, Анекдот!

Я знал программиста, который думал о $_REQUEST место для простого хранения данных, которые были доступны суперглобальным способом. Важные имена пользователей и пароли, пути к файлам, вы называете его, и он был сохранен в $_REQUEST, Он был немного удивлен (хотя, к сожалению, не так комично), когда я рассказал ему, как ведет себя эта переменная. Излишне говорить, что эта практика была свергнута.

$_REQUEST относится ко всем видам запросов (GET, POST и т. д.). Иногда это полезно, но обычно лучше указать точный метод ($_GET, $_POST и т. Д.).

GET-запросы должны быть идемпотентными, а POST-запросы - нет. Это означает, что данные в $_GET а также $_POST как правило, следует использовать по-разному.

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

Это расплывчато Вы на самом деле не знаете, как данные поступили к вам, так как они содержат данные о постах, получении и cookie. Я не обязательно думаю, что это всегда плохо, если только вам не нужно знать или ограничивать способ доставки.

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

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

ЭТА:

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

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

Единственное время использования $_REQUEST неплохая идея с GET.

  • Если вы используете его для загрузки значений POST, вы рискуете подделать межсайтовый запрос
  • Если вы используете его для загрузки значений cookie, вы снова рискуете подделкой межсайтовых запросов

И даже с GET, $_GET короче тип, чем $_REQUEST;)

Важно понимать, когда использовать POST, когда использовать GET, а когда использовать cookie. С $_REQUEST значение, на которое вы смотрите, могло бы прийти от любого из них. Если вы ожидаете получить значение из POST или GET или из COOKIE, для кого-то, кто читает ваш код, более информативно использовать конкретную переменную вместо $_REQUEST.

Кто-то еще также указал, что вы не хотите, чтобы все POST или файлы cookie были переопределены GET, потому что для всех них существуют разные межсайтовые правила, например, если вы возвращаете данные ajax при использовании $_REQUEST, вы уязвимы на межсайтовую скриптовую атаку.

Даррен Кук: "Начиная с php 5.3, по умолчанию php.ini говорит, что только данные GET и POST помещаются в $_REQUEST, Смотрите http://php.net/request_order Я только что наткнулся на этот разрыв обратной совместимости, ожидая, что данные cookie будут в $_REQUEST и интересно, почему это не работает!

Ух ты... только что некоторые из моих скриптов перестали работать из-за обновления до PHP 5.3. Сделал то же самое: предположим, что куки будут установлены при использовании $_REQUEST переменная. С апгрейдом точно, что перестало работать.

Я теперь вызываю значения cookie отдельно, используя $_COOKIE["Cookie_name"]...

Я думаю, что нет проблем с $_REQUEST, но мы должны быть осторожны при его использовании, так как это набор переменных из 3 источников (GPC).

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

// delete $_REQUEST when program execute, the program would be lighter 
// when large text submitted
unset($_REQUEST);

// wrapper function to get 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 {
    // no source specified, then find in 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; 
    } 
  }
}

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

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

Помимо проблем безопасности и WTF, вызванных файлами cookie и переменными среды в переменной REQUEST (не заставляйте меня начинать работу с GLOBAL), подумайте о том, что может произойти в будущем, если PHP начнет поддерживать другие методы, такие как PUT и DELETE. Хотя крайне маловероятно, что они будут объединены в суперглобальный объект REQUEST, возможно, они могут быть включены как опция в настройке variable_order. Таким образом, вы действительно не имеете ни малейшего представления о том, что держит REQUEST и что имеет приоритет, особенно если ваш код развернут на стороннем сервере.

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

Я мог бы быть использован, только если вы хотите получить текущий URL или имя хоста, но для фактического анализа данных с этого URL, таких как параметры с использованием символа &, это, вероятно, не очень хорошая идея. В общем, вы не хотите использовать расплывчатое описание того, что вы пытаетесь сделать. Если вам нужно быть конкретным, то здесь $_REQUEST плох, если вам не нужно быть конкретным, не стесняйтесь использовать его. Я бы подумал.

Просто убедитесь, что вы установили правильный параметр в вашем php.ini (ниже это значение по умолчанию, если не установлено значение GPC, здесь файлы cookie не используются)

request_order = "GP"

что означает, что POST перезаписывает GET, и все будет в порядке.

Причина для $_REQUESTэто просто объединение $_GET и $_POST. При отправке формы и навигации по множеству ссылок на вашей странице очень полезно иметь одно место, в котором хранится состояние: $_REQUEST

Основная проблема заключается в том, что он содержит куки, как уже говорили другие.

В PHP 7 вы можете сделать это:

$request = array_merge($_GET ?? [], $_POST ?? []);

Это позволяет избежать проблемы с cookie и в худшем случае дает пустой массив, а в лучшем случае слияние $_GET и $_POST, причем последний имеет приоритет. Если вы не слишком обеспокоены разрешением вставки URL параметров через строку запроса, это довольно удобно.

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

Другие вопросы по тегам