PHP에서 HTTP_HOST와 SERVER_NAME의 차이점은 무엇입니까?


533

PHP HTTP_HOSTSERVER_NAMEPHP 의 차이점은 무엇입니까 ?

어디:

  • HTTP_POST === $_SERVER['HTTP_HOST']
  • SERVER_NAME === $_SERVER['SERVER_NAME']

언제 다른 것을 사용하는 것이 좋을까요?


14
"일반적으로 HTTP_HOST를 사용하여 사용자가 시작한 정확한 호스트 이름을 유지합니다. 예를 들어 .com 및 .org 도메인에 동일한 사이트가있는 경우 .org에서 .com, 특히 .org에 로그인 토큰이있을 경우 다른 도메인으로 보내면 손실 될 수 있습니다. " -이것과 stackoverflow.com/questions/1459739/…의
Yarin

5
@Yarin, 의 결과HTTP_HOST허용 목록에 포함시키는 것을 잊지 마십시오 . 그렇지 않으면 공격자에 넣을 수 있는 는 HTTP의 가치 Host:요청하고 서버에서 동의합니다.
Pacerier

6
초보자 :이 질문은 다음을 통해 $_SERVER['HTTP_HOST']또는 일반적으로 얻은 값을 $_SERVER['SERVER_NAME']
말합니다.

답변:


780

HTTP_HOST으로부터 얻을 수 HTTP 요청 헤더 와이 클라이언트가 실제로 요청 "대상 호스트"로 사용되는 것입니다. 은 SERVER_NAME서버 설정에 정의되어 있습니다. 어떤 것을 사용해야하는지에 따라 다릅니다. 그러나 이제는 하나가 비즈니스 제어에 사용하기에 신뢰할 수없는 클라이언트 제어 값이고 다른 하나는보다 안정적인 서버 제어 값임을 인식해야합니다. 그러나 해당 웹 서버가 SERVER_NAME올바르게 구성 되어 있는지 확인해야 합니다. Apache HTTPD를 예로 들어, 다음 은 문서 에서 추출한 것입니다 .

no ServerName를 지정하면 서버는 IP 주소에서 역방향 조회를 수행하여 호스트 이름을 추론하려고 시도합니다. 에 포트가 지정되어 있지 않으면 ServerName서버는 들어오는 요청의 포트를 사용합니다. 최적의 안정성과 예측 성을 위해서는 ServerName지시문을 사용하여 명시적인 호스트 이름과 포트를 지정해야 합니다.


업데이트 : 귀하의 질문에 Pekka의 답변을 확인한 후 PHP가 항상 의 가치를 반환한다는 bobince의 답변에 대한 링크가 포함되어 있습니다 .2 년 전의 내 PHP 4.x + Apache HTTPD 1.2.x 경험에 반합니다. , 나는 Windows XP (PHP 5.2.8의 Apache HTTPD 2.2.1)에서 현재 XAMPP 환경에서 약간의 먼지를 날려 시작하여 두 값을 인쇄하는 PHP 페이지를 만들고 헤더 를 수정하는 데 사용하는 Java 테스트 응용 프로그램을 만들었습니다. 테스트는 이것이 실제로 (잘못된) 사례라고 가르쳐주었습니다.HTTP_HOSTSERVER_NAMEURLConnectionHost

먼저 PHP를 의심 하고 주제에 관한 일부 PHP 버그 보고서 를 파고 Host들었을 때 문제의 근본이 웹 서버에서 사용되어 SERVER_NAME요청 시 HTTP 헤더를 잘못 반환한다는 것을 알았습니다 . 그래서 주제에 관한 다양한 키워드 를 사용하여 Apache HTTPD 버그 보고서 를 파헤 쳤고 마침내 관련 버그를 발견했습니다 . 이 동작은 Apache HTTPD 1.3부터 ​​도입되었습니다. 당신은 설정에 필요 에 지시 에서 의 항목 에서 (또한 하단의 경고 확인 문서를 !).UseCanonicalNameon<VirtualHost>ServerNamehttpd.conf

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

이것은 나를 위해 일했습니다.

요약하면 SERVER_NAME더 안정적이지만 서버 구성에 의존 합니다!


5
좋아, 이것은 내 문제를 해결합니다. OP와 관련이 없지만 관련이 있습니다. 브라우저가 제공 할 수있는 모든 것을 사용하여 보안 문제에 대해 매우 우려하고있었습니다. 이 답변은 큰 도움이되었습니다. 함께 시간을내어 주셔서 감사합니다.
Yitzhak

2
왜 HTTP_HOST가 신뢰할 수 없다고 말합니까? 예, 사용자가 제공하지만 사용자가 가짜 값을 제공하면 서버 구성이 자동으로 503을 반환하고 PHP 스크립트가 실행되지 않습니다!
Pacerier

1
@Pacerier :이 답변을 작성할 당시에는 그렇지 않았습니다. 답변에 버전이 언급되어 있습니다. 더 이상 PHP를 사용하지 않으므로 최신 버전으로 변경되었는지 말할 수 없습니다.
BalusC

2
WinXP에서 Apache를 속이는 쉬운 방법은 'hosts'파일에 서버의 IP가 "127.0.0.1 mydomain.com"과 같은 다른 도메인에 할당되었음을 나타내는 줄을 추가하는 것입니다. 인터넷 연결과 사이트로드 속도가 매우 빠르다고 생각하도록 청중을 속이는 로컬 웹 사이트를 보여주기 위해이 과정을 여러 번 사용했습니다. 다른 방법으로 가서 "173.194.41.5 localhost"를 사용하여 Apache가 로컬에서 실행되고 있다고 생각하도록 속일 수 있으므로 Apache가 제대로 구성되어 있지 않다면 SERVER_NAME을 완전히 신뢰해서는 안됩니다.
vicenteherrera

1
NGINX + PHP-FPM이 server_name지시문에 의해 설정된 값을 반환한다는 것을 추가하고 싶습니다 . 특히 no server_name가 설정되어 _SERVER["SERVER_NAME"]있으면 비어 있습니다.
white_gecko

69

HTTP_HOST클라이언트가 보낸 대상 호스트입니다. 사용자가 자유롭게 조작 할 수 있습니다. 사이트에 HTTP_HOST값을 요청하는 요청을 보내는 것은 문제가되지 않습니다 www.stackoverflow.com.

SERVER_NAME서버의 VirtualHost정의 에서 나오므로보다 안정적인 것으로 간주됩니다. 그러나 웹 서버 설정 방법과 관련된 특정 조건 하에서 외부에서 조작 할 수도 있습니다 .이 두 가지 변형의 보안 측면을 다루는 이 SO 질문 을 참조하십시오 .

안전하기 위해 의존해서는 안됩니다. 즉, 사용하는 것은 실제로 원하는 일에 달려 있습니다. 스크립트가 실행중인 도메인을 확인하려는 경우 HTTP_HOST악의적 인 사용자가 제공 한 잘못된 값이 아무 것도 깨지지 않는 한 안전하게 사용할 수 있습니다.


8
예. 그러나 대부분의 HTTP 서버는 HTTP_HOST 값 www.stackoverflow.com을 요청하는 요청을 거부하므로 PHP 스크립트는 요청을 보지 못합니다!
Pacerier

2
@Pacerier true이지만 서버가 올바르게 구성되지 않은 경우 항상 그런 것은 아닙니다.
Pekka

1
BalusC의 게시물에서 언급했듯이 IP로 Apache 가상 호스트에 액세스하면 이 변수 모두 실제 서버 이름이 아닌 IP (기본적으로)를 포함합니다. 실제 서버 이름 이되도록하려면 UseCanonicalName onhttpd.conf 에서 사용해야 SERVER_NAME합니다.
Simon East

@Pekka 웃, 서버가 올바르게 구성 $_SERVER['SERVER_NAME']되지 않으면 작동하지 않습니다 . 잘못 구성된 서버는 $_SERVER['SERVER_NAME']클라이언트 Host:요청 값에 따라 설정됩니다 . 둘 다 동일합니다.
Pacerier

좋은 대답이지만 가상 호스팅을 가정하지는 않습니다.
Anthony Rutledge

55

이 답변 에서 언급했듯이 서버가 80 이외의 포트에서 실행되는 경우 (개발 / 인트라넷 컴퓨터에서 일반적 일 수 있음) HTTP_HOST포트가 포함되어 있지만 SERVER_NAME그렇지 않습니다.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(적어도 아파치 포트 기반 가상 호스트에서 눈치 채 셨을 것입니다)

참고 HTTP_HOST않습니다 하지 포함 :443HTTPS에서 실행되는 경우 (당신은 내가 테스트하지 않은 비표준 포트에서 실행하지 않는 한).

다른 사람들이 지적했듯이 IPv6을 사용할 때 두 가지도 다릅니다.

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'

2
그들은이 교활한 행동을 언제 고칠 것인가?
Pacerier

27

당신이 IPv6를 사용하려는 경우, 당신은 아마 사용하려는 있습니다 HTTP_HOST보다는 SERVER_NAME. http://[::1]/환경 변수 를 입력 하면 다음과 같습니다.

HTTP_HOST = [::1]
SERVER_NAME = ::1

이는 예를 들어 mod_rewrite를 수행하면 불쾌한 결과를 얻을 수 있음을 의미합니다. SSL 리디렉션의 예 :

# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/

# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/

호스트 이름없이 서버에 액세스하는 경우에만 적용됩니다.


1
SiteGround의 내부 HTTP에서 https 로의 리디렉션 코드에서https://%{SERVER_NAME}%{REQUEST_URI}
IXN

6

server.php 등을 통해 확인하려면 다음과 같이 호출하십시오.

<?php
    phpinfo(INFO_VARIABLES);
?>

또는

<?php
    header("Content-type: text/plain");

    print_r($_SERVER);
?>

그런 다음 사이트에 유효한 모든 URL로 액세스하여 차이점을 확인하십시오.


5

내가 찾고 싶은 것에 달려 있습니다. SERVER_NAME은 서버의 호스트 이름이며 HTTP_HOST는 클라이언트가 연결된 가상 호스트입니다.


4
정확한 사실 SERVER_NAME은 아닙니다. Rowland 는 일반적으로 서버 자체가 아닌 VirtualHost의 이름입니다. 그리고 Apache에서는 SERVER_NAME종종 같은 값으로 채워집니다 HTTP_HOST(BarusC의 답변 참조).
Simon East

1
@Simon, 대부분의 호스트는 이제 VirtualHost이므로 "서버 자체"라는 이름은 무엇을 의미합니까?
Pacerier

하나의 웹 사이트로 가상 사설 서버 (VPS)를 실행중인 경우 SERVER_NAME가상 호스트에 해당한다고 가정 할 필요가 없습니다 . 그러나 여전히 한 사이트에 가상 호스트 설정을 사용할 수 있습니다. 많은 사람들이 공유 호스팅을 사용하므로 요점을 알 수 있습니다.
Anthony Rutledge

2

사람들이 ' SERVER_NAME신뢰할 수있는 것'의 의미를 이해하는 데 시간이 걸렸습니다 . 공유 서버를 사용하고 가상 호스트 지시문에 액세스 할 수 없습니다. 그래서 mod_rewrite를 사용 하여 다른 디렉토리를 다른 디렉토리 .htaccess 에 매핑 HTTP_HOST합니다. 이 경우 HTTP_HOST의미가 있습니다.

이름 기반 가상 호스트를 사용하는 경우와 비슷한 상황입니다. ServerName 내의 지시문은이 가상 호스트에 매핑 될 호스트 이름 만 나타냅니다. 결론적으로, 두 경우 모두 요청 ( HTTP_HOST) 동안 클라이언트가 제공 한 호스트 이름은 서버 내 이름과 일치해야하며,이 이름은 자체적으로 디렉토리에 매핑됩니다. 매핑이 가상 호스트 지시어 또는 htaccess mod_rewrite 규칙으로 수행되는지 여부는 부차적입니다. 이 경우 HTTP_HOST와 같습니다 SERVER_NAME. 아파치가 그런 식으로 구성되어 기쁘다.

그러나 상황은 IP 기반 가상 호스트와 다릅니다. 이 경우에만이 경우, SERVER_NAME그리고 HTTP_HOST지금은 클라이언트가 아니라 이름의 IP에서 서버를 선택하기 때문에 다를 수 있습니다. 실제로 이것이 중요한 특별한 구성이있을 수 있습니다.

따라서 지금부터는 SERVER_NAME코드가 이러한 특수 구성으로 이식되는 경우를 대비하여을 사용합니다.


2

하나는 간단한 설정 (CentOS 7, Apache 2.4.x 및 PHP 5.6.20)을 가지고 있고 하나의 웹 사이트 만 (가상 호스팅을 가정하지 않음) 가정합니다 ...

PHP 의미에서, $_SERVER['SERVER_NAME']PHP 는 httpd.conf $_SERVER의 아파치 구성 (으로 **ServerName**지시어 UseCanonicalName On)을 기반으로 슈퍼 글로벌에 등록 된 요소입니다 ( 포함 된 가상 호스트 구성 파일 등). HTTP_HOST 는 HTTP에서 파생됩니다host 헤더 . 이것을 사용자 입력으로 취급하십시오. 사용하기 전에 필터링하고 확인하십시오.

다음은 $_SERVER['SERVER_NAME']비교의 기준으로 사용하는 예입니다 . 다음 방법은 이름이 ServerValidator(child of Validator) 인 구체적인 자식 클래스에서 온 것입니다 . ServerValidator$ _SERVER에서 6 ~ 7 개의 요소를 사용하기 전에 점검합니다.

HTTP 요청이 POST인지 확인하기 위해이 방법을 사용합니다.

public function isPOST()
{
    return (($this->requestMethod === 'POST')    &&  // Ignore
            $this->hasTokenTimeLeft()            &&  // Ignore
            $this->hasSameGETandPOSTIdentities() &&  // Ingore
            ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}

이 메소드가 호출 될 때 관련 $ _SERVER 요소 (및 관련 특성 세트)의 모든 필터링 및 유효성 검증이 발생했습니다.

라인 ...

($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')

... $_SERVER['HTTP_HOST'](요청 된 hostHTTP 헤더 에서 최종적으로 파생 된) 값이 일치 하는지 확인합니다 $_SERVER['SERVER_NAME'].

지금, 나는 내 예를 설명하기 위해 자동 전역 말하는을 사용하고 있지만, 어떤 사람들은 익숙하지 않은 단지 때문입니다 INPUT_GET, INPUT_POST그리고 INPUT_SERVER안부에 filter_input_array().

결론은하지 않는 내 서버에 POST 요청을 처리하지 않는 것입니다 모두 네 가지 조건이 충족된다. 따라서, POST 요청의 측면에서, 실패는 HTTP 제공하는 host헤더 주문 (이전 테스트 존재) 의 운명 엄격한 위해 HTTP 1.0 브라우저. 또한, 요청 된 호스트 값과 일치해야합니다 위해 ServerName에서 httpd.conf를 들어, 확장자에 의해, 값을, 그리고 $_SERVER('SERVER_NAME')에서 $_SERVER자동 전역. 다시 한 번, INPUT_SERVERPHP 필터 기능과 함께 사용 하지만 드리프트를 잡습니다.

아파치 가 아니더라도 Apache ServerName표준 리다이렉션 (예 : 후행 슬래시를 URL에서 남기는 등)을 자주 사용합니다 (예 : http://www.foo.comhttp://www.foo.com/ ). URL 재 작성 사용

내가 $_SERVER['SERVER_NAME']아닌 표준으로 사용 합니다 $_SERVER['HTTP_HOST']. 이 문제에는 많은 부분이 있습니다. $_SERVER['HTTP_HOST']비어있을 수 있으므로 위의 공개 방법과 같은 코드 규칙을 작성하기위한 기초가되어서는 안됩니다. 그러나, 둘 다 설정 될 수 있다고해서 이들이 동일하다는 것을 보장하지는 않습니다. 테스트는 아는 가장 좋은 방법입니다 (Apache 버전 및 PHP 버전을 염두에 두어야 함).


0

balusC가 말했듯이 SERVER_NAME은 신뢰할 수 없으며 아파치 구성, 서버의 서버 이름 구성 및 사용자와 서버 사이에있을 수있는 방화벽에서 변경할 수 있습니다.

다음 함수는 항상 포트없이 실제 호스트 (사용자 유형 호스트)를 반환하며 거의 신뢰할 수 있습니다.

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}

0

$ _SERVER [ 'SERVER_NAME'] 은 (는) 웹 서버 구성을 기반으로합니다. $ _SERVER [ 'HTTP_HOST'] 는 클라이언트의 요청을 기반으로합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.