Какие переменные $_SERVER безопасны?

Любая переменная, которую пользователь может контролировать, злоумышленник также может контролировать и, следовательно, является источником атаки. Это называется "испорченной" переменной и небезопасно.

При использовании $_SERVER многие из переменных можно контролировать. PHP_SELF, HTTP_USER_AGENT, HTTP_X_FORWARDED_FOR, HTTP_ACCEPT_LANGUAGE и многие другие являются частью заголовка HTTP-запроса, отправленного клиентом.

Кто-нибудь знает о "безопасном списке" или незанятом списке переменных $_SERVER?

Ответ 1

Нет таких вещей, как "безопасные" или "небезопасные" значения как таковые. Существуют только значения, которые сервер контролирует и значения, которые пользователь контролирует, и вам нужно знать, откуда приходит значение, и, следовательно, можно ли им доверять в определенной цели. $_SERVER['HTTP_FOOBAR'], например, полностью безопасно хранить в базе данных, но я, безусловно, не был бы eval.

Таким образом, разделим эти значения на три категории:

Управляемый сервером

Эти переменные устанавливаются средой сервера и полностью зависят от конфигурации сервера.

  • 'GATEWAY_INTERFACE'
  • 'SERVER_ADDR'
  • 'SERVER_SOFTWARE'
  • 'DOCUMENT_ROOT'
  • 'SERVER_ADMIN'
  • 'SERVER_SIGNATURE'

Частично контролируемый сервер

Эти переменные зависят от конкретного запроса, отправленного клиентом, но могут принимать только ограниченное число допустимых значений, так как все недопустимые значения должны быть отклонены веб-сервером и не должны вызывать обращение к script. Следовательно, их можно считать надежными.

  • 'HTTPS'
  • 'REQUEST_TIME'
  • 'REMOTE_ADDR' *
  • 'REMOTE_HOST' *
  • 'REMOTE_PORT' *
  • 'SERVER_PROTOCOL'
  • 'HTTP_HOST'
  • 'SERVER_NAME'
  • 'SCRIPT_FILENAME'
  • 'SERVER_PORT'
  • 'SCRIPT_NAME'

* Значения REMOTE_ гарантированы как действительный адрес клиента, подтвержденный рукопожатием TCP/IP. Это адрес, на который будет отправлен любой ответ. REMOTE_HOST полагается на обратные запросы DNS, хотя и может быть подделан атаками DNS на ваш сервер (в этом случае у вас есть большие проблемы). Это значение может быть прокси-сервером, который представляет собой простую реальность протокола TCP/IP, и вы ничего не можете сделать.

† Если ваш веб-сервер отвечает на любой запрос независимо от заголовка HOST, это также следует считать небезопасным. См. Насколько безопасно $_SERVER [ "HTTP_HOST" ]?.
Также см. http://shiflett.org/blog/2006/mar/server-name-versus-http-host.

‡ См. https://bugs.php.net/bug.php?id=64457, http://httpd.apache.org/docs/current/mod/core.html#usecanonicalphysicalport, http://httpd.apache.org/docs/2.4/mod/core.html#comment_999

Полностью произвольные контролируемые пользователем значения

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

  • 'argv', 'argc' (применимо только к вызову CLI, обычно не относится к веб-серверам)
  • 'REQUEST_METHOD' §
  • 'QUERY_STRING'
  • 'HTTP_ACCEPT'
  • 'HTTP_ACCEPT_CHARSET'
  • 'HTTP_ACCEPT_ENCODING'
  • 'HTTP_ACCEPT_LANGUAGE'
  • 'HTTP_CONNECTION'
  • 'HTTP_REFERER'
  • 'HTTP_USER_AGENT'
  • 'AUTH_TYPE'
  • 'PHP_AUTH_DIGEST'
  • 'PHP_AUTH_USER'
  • 'PHP_AUTH_PW'
  • 'PATH_INFO'
  • 'ORIG_PATH_INFO'
  • 'REQUEST_URI' (может содержать испорченные данные)
  • 'PHP_SELF' (может содержать испорченные данные)
  • 'PATH_TRANSLATED'
  • любое другое значение 'HTTP_'

§ Может считаться надежным, если веб-сервер допускает только определенные методы запроса.

‖ Может считаться надежным, если аутентификация полностью обрабатывается веб-сервером.

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

Ответ 2

В PHP на каждую переменную $_SERVER, начинающуюся с HTTP_, может влиять пользователь. Например, переменная $_SERVER['HTTP_REINERS'] может быть испорчена установкой HTTP-заголовка REINERS произвольному значению в HTTP-запросе.