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

97

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

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

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

ладья
источник
8
Зависит от того, как вы определяете «безопасный». Все значения безопасны сами по себе, это зависит только от того, для чего вы их используете.
deceze
6
Я думаю, что в этом контексте Рук говорит: «Какие серверные переменные не могут быть подделаны пользователем», например REMOTE_ADDR.
vcsjones
6
Все, что предшествует, HTTP_является заголовком запроса и может быть установлено браузером или прокси-сервером между ними. Я бы рассмотрел их как любой другой пользовательский ввод.
данные
3
@bob-the-destroyer REMOTE_ADDR извлекается непосредственно из TCP-сокета apache, это значение нельзя подделать через Интернет из-за трехстороннего рукопожатия.
ладья
2
@Rook: хороший момент. Думаю, с упоминанием «спуфинга» я больше склонялся к старому акту подмены IP-адресов, а не к подделке фактического значения REMOTE_ADDR. И это выходит за рамки этого вопроса. Хорошо, если вы разобрались, как устанавливается это значение, поэтому спасибо.
bob-the-destroyer

Ответы:

147

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

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

Сервер контролируется

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

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

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

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

  • '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также включает несколько переменных среды. Являются ли они «безопасными» или нет, зависит от того, как (и где) они определены. Они могут варьироваться от полностью контролируемых сервером до полностью управляемых пользователем.

обмануть
источник
3
@Rook Но, как я уже сказал, это абсолютно зависит от того, как вы его используете . Сами по себе ценности не являются ни безопасными, ни небезопасными, это зависит от того, для чего вы их используете . Даже данные, отправленные злонамеренным пользователем, совершенно безопасны, если вы не делаете с ними ничего, что может поставить под угрозу вашу безопасность.
deceze
2
@Rook: ваше представление о «безопасном» заставляет этот вопрос казаться несколько произвольным, тем более, что он полностью привязан к неясному расширению или специальной версии PHP. В то время как вы говорите, что «не следует« стрелять с бедра »», для любого ответа на самом деле, кажется, требуется как минимум знакомство с исходным кодом PHP, чтобы узнать, как эти значения установлены. Разве электронная почта разработчикам PHP не лучший способ найти ответ?
bob-the-destroyer
2
@Rook: Непонимание. Как намекнул deceze, «безопасно для каких целей». Как я намекал, ваша цель неизвестна, и, кроме того, есть несколько других недокументированных $_SERVERзначений в зависимости от того, как файл обслуживается. На мой взгляд, задокументированные не проясняют истинный источник. Иначе я думаю, вы бы не задавали этот вопрос. Рад, что у вас есть список, который вы можете использовать. Но я все же предлагаю отправить отчет об ошибке (когда их сайт с ошибкой будет исправлен), отправить разработчикам документации электронное письмо или обновить документы самостоятельно (если вы знакомы с ссылкой). Сообществу было бы полезно знать эту информацию.
bob-the-destroyer
3
SERVER_NAMEне обязательно контролируется сервером. В зависимости от шлюза и настроек он может быть дублирован HTTP_HOSTи, следовательно, с той же оговоркой.
bobince
1
@deceze @ Ладья А SERVER_PORTэтот крестик нужен? bugs.php.net/bug.php?id=64457
Деян Марьянович
12

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

Райнерс
источник
re "произвольный"; Не все произвольно, поскольку они соответствуют формату. Например, $_SERVER['HTTP_REINERS'] в большинстве sapis не может содержать символы новой строки.
Pacerier