Что не так с использованием $ _REQUEST []? - PullRequest
115 голосов
/ 26 января 2010

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

Ответы [ 15 ]

183 голосов
/ 27 января 2010

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

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

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

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

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

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

71 голосов
/ 27 января 2010

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

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

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

и в позже ответит на тот женить

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

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

И заразить вас 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 для параметра variable_order ini сообщает нам:

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 Internals

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

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

10 голосов
/ 26 января 2010

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

8 голосов
/ 27 января 2010

$_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. Запросы на определенные типы данных без прав доступа или с низким уровнем привилегий (например, динамически генерируемые изображения карты) могут обслуживаться в ответ на запросы любого из методов.

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

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

EDIT:

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

П.С., Анекдот!

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

8 голосов
/ 26 января 2010

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

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

7 голосов
/ 26 января 2010

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

3 голосов
/ 26 января 2010

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

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

ETA :

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

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

2 голосов
/ 26 января 2010

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

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

2 голосов
/ 26 января 2010

Единственный раз, когда используется $_REQUEST, неплохая идея - это GET.

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

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

0 голосов
/ 18 января 2019

Основная проблема в том, что в нем содержатся файлы cookie, как уже говорили другие.

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

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

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

...