Netadmin.ws

GET и POST - чем отличаются, как использовать, вопросы безопасности
Дата: 08.07.2003 - 04:34
Тема: Программирование
Этот материал предназначен для новичков. В нем объясняется как сценарий PHP может получить данные от пользователя и что можно сделать потом.




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

В спецификации HTTP/1.1 определены следующие методы запросов которые клиент может использовать:
HEAD
GET
POST
LINK
UNLINK
PUT
DELETE
OPTIONS
TRACE
CONNECT (только https)

Нас интересуют GET и POST. Можно было бы еще обсудить и PUT но он достаточно редко используется. Если вас интересуют определения прочих методов перечисленных в списке, обратитесь к спецификации HTTP/1.1 (RFC 2068)

Что такое метод HTTP?
quote:

Метод - это команда HTTP, с которой начинается первая строка клиентского запроса. Метод сообщает серверу о цели клиентского запроса. Практически все серверы поддерживают методы HEAD GET POST. Поддержка остальных методов не всегда реализована. Названия методов регистрозависимые (get != GET)



В последних версиях PHP имеется несколько масивов (если track_vars On [в PHP 4.0.3 всегда On, вне зависимости от файла конфигурации]):
$_GET - переменные GET запроса
$_POST - переменные POST запроса
$_FILES - информация о файлах загружаемых методом HTTP POST

Вышеперечисленные имена - это более короткие имена стандартных массивов которые есть и в более ранних и текущей версиях PHP:
$HTTP_GET_VARS
$HTTP_POST_VARS
$HTTP_POST_FILES

Разницы между данными нет, разница только в имени с помощью которого можно получить доступ (т.е. $_GET['text'] === $HTTP_GET_VARS['text'])

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

Как определить метод запроса?

Напрямую:

PHP:

getenv
('REQUEST_METHOD');


вернет [ HEAD | GET | POST| PUT] один из перечисленных.

Косвенным путем (не всегда и не все методы):
например: если есть QUERY_STRING(это не всегда правильно - строка запроса может отсутствовать при запросе методом GET) это метод GET, если есть CONTENT_LENGTH - это POST и т.д.

метод GET
Чтобы передать данные методом GET не надо создавать на HTML странице форму(использовать формы для запросов методом GET вам никто не запрещает - но это тупость) - достаточно ссылки на документ с добавлением строки запроса которая может выглядеть как переменная=значение пары объединяются с помощью амперсанда & а к URL страницы строка присоединяется с помощью вопросительного знака ?

Но можно не использовать пары ключ=значение если надо передать всего одну переменную для этого надо после знака вопроса написать ЗНАЧЕНИЕ(не имя) переменной. В сценарии доступ к этому значению выглядит так:

PHP:

$my_var 
getenv('QUERY_STRING');


при этом массив $_GET будет пустым

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

Недостаток в том, что просто изменив параметры в адресной строке пользователь может повернуть ход сценария непредсказуемым образом, это создает огромную дыру в безопасности в сочетании с неопределенными переменными и register_globals On или кто нибудь может узнать значение важной переменной(например ID сесии) просто посмотрев на экран монитора(или скриншот который сделан с помошью трояна :))).

Для чего следует использовать:

- для доступа к общедоступным страницам с передачей параметров (повышение функциональности)
- передача информации не влияющей на уровень безопасности

Для чего не следует использовать

- для доступа к защищенным страницам с передачей параметров
- для передачи информации влияющей на уровень безопасности
- для передачи информации не подлежащей модифицированию пользователем (некоторые передают текст SQL запросов[что само по себе вопиющие нарушение правил ТБ] в БД с помощью этого метода =)

метод POST

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

PHP:

getenv
('HTTP_REFERER');

(о вопросах безопасности чуть позже)

Преимущество:
- большая безопасность и функциональность запросов с помощью форм методом POST

Недостаток:
- меньшая доступность

Для чего следует использовать:

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

Для чего не следует использовать:

- для затруднения юзабельности сайта =)

О структуре массива $_FILES

структура приблизительно следующая...

PHP:

$_FILES 
= array(
    [
'имя поля формы'] array (
         [
'name'] = 'имя файла у клиента без пути',
         [
'type'] = 'тип содержимого MIME',
         [
'tmp_name'

'временное имязагруженного файла на диске сервера',
         [
'size'] = 'размер в байтах'
    
)
);



Еще о массивах
Существет так же массив $_REQUEST
В нем объединено содержимое массивов $_GET $_POST $_COOKIE (NOTES В ТЕМУ: я не проверял этот факт, но логично предположить что если в $_GET и $_COOKIE есть переменные с одинаковыми именами то в $_REQUEST они перезаписывают друг друга в соответствии с директивой конфигурации variables_order).

О безопасности связанной с приемом переменных извне

Я, при разработке web-приложений на PHP соблюдаю всего три правила ТБ (тб - сокр. от техника безопасности):
- не верить никому
- все проверять
- если невозможно проверить -> отказать в доступе или выполнить действие по умолчанию

Как априори(постоянная не требующая доказательств) считаю, что не существует нормальных пользователей, есть только злобные хацкеры, спаммеры, флудеры и хулиганы которых хлебом не корми, только дай напихать в форму всякой гадости типа HTML тегов или JavaScript, подделать REFERER и еще много всего нехорошего...

Проверка HTTP_REFERER не дает абсолютной защититы от изменения данных, потому что ее можно подделать. По ней можно лишь определить откуда пришел пользователь и не более того, но все же стоит ее проверять при приеме ЛЮБЫХ ЗАПРОСОВ МЕТОДОМ POST

Далее определите требования к данным которые вы получаете и проверьте их при приеме.

При проверке вы можете получить всего два значения:
- данные валидны
- данные не валидны

Если данные не валидны, надо принять решение, что делать дальше:
- ничего, просто теперь известно что данные неправильные
- привести данные в требуемый вид в сответствии с инструкцией

В теме Сказка про PHP скрипт описаны две функции:
set_valid и is_valid
is_valid - просто проверяет соответствуют ли данные набору правил, а set_valid исправляет данные если они не соответствуют набору правил(требованиям).

Наборы правил и действий по исправлению не заданы внутри функций и должны передаваться как параметры, это позволяет конструировать проверки любой сложности создавая свои функции и хранить все в одном месте не раскидывая по коду скрипта...


Напоследок...(для более продвинутых)
в одной из тем обсуждали с polo ошибку условия. Условие было истинным если переменная есть в куках ее не должно быть в GET или POST. Эта дискуссия навела меня на одну мысль в районе зачем нужны куки и данные запроса и как их разграничить. Возможно позже развернуто объясню свое мнение по этому вопросу.
Место где находиться переменаая, в $_GET или $_POST указывает лишь на метод, а $_COOKIE - это однозначно данные.

Нужно не заглядывать в массивы, проверяя значение переменной, а знать две вещи:
- было ли что то передано
- есть ли в нем то что нам надо
В соответствии с этим можем разделить запросы не зависимо от метода на две группы:
- запрос с передачей данных от клиента
- запрос без передачи данных

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

При приеме данных лишь определяем требование каким методом должны быть переданы (GET или POST) данные от клиента к серверу...

P.S.
Если после прочтения этой статьи в ваших скриптах станет меньше хотя бы на одну ошибку, я могу считать что не зря возился с этим сообщением почти час =)

Оюсуждение статьи: http://netadmin.ws/forum/showthread...=&threadid=2413


Эта статья находится по адресу:
http://netadmin.ws/article.php?sid=43