복붙노트

PHP $ _SERVER [ 'HTTP_HOST'] 대 $ _SERVER [ 'SERVER_NAME'], 맨 페이지를 제대로 이해하고 있습니까?

PHP

PHP $ _SERVER [ 'HTTP_HOST'] 대 $ _SERVER [ 'SERVER_NAME'], 맨 페이지를 제대로 이해하고 있습니까?

나는 많은 검색을했고 PHP $ _SERVER 문서도 읽었습니다. 내 사이트 전체에서 사용되는 간단한 링크 정의를 위해 PHP 스크립트에 사용할 권한과 관련하여이 권리가 있습니까?

$ _SERVER [ 'SERVER_NAME']은 웹 서버의 구성 파일 (제 경우에는 Apache2)을 기반으로하며, (1) VirtualHost, (2) ServerName, (3) UseCanonicalName 등 몇 가지 지시문에 따라 다릅니다.

$ _SERVER [ 'HTTP_HOST']는 클라이언트의 요청을 기반으로합니다.

그러므로 가능한 한 내 스크립트를 호환 가능하게 만드는 데 사용할 적절한 것이 $ _SERVER [ 'HTTP_HOST'] 일 것입니다. 이 가정이 맞습니까?

추가 답변 :

나는이 기사를 읽은 다음 약간의 사람들이 "$ _SERVER vars 중 어떤 것도 믿지 않을 것"이라고 말한 후 조금 편집증 적이라고 생각합니다.

분명히 토론은 주로 $ _SERVER [ 'PHP_SELF']에 대한 것이고 XSS 공격을 막기위한 적절한 이스케이프 처리가없는 경우 양식 활동 속성에서 사용해서는 안되는 이유입니다.

위의 원래 질문에 대한 내 결론은 양식에서 사용되는 경우에도 XSS 공격에 대해 걱정할 필요없이 사이트의 모든 링크에 $ _SERVER [ 'HTTP_HOST']를 사용하는 것이 "안전"하다는 것입니다.

내가 틀렸다면 나를 바로 잡아주세요.

해결법

  1. ==============================

    1.아마 모두가 처음 생각합니다. 그러나 조금 더 어려워. Chris Shiflett의 SERVER_NAME 대 HTTP_HOST 문서를 참조하십시오.

    아마 모두가 처음 생각합니다. 그러나 조금 더 어려워. Chris Shiflett의 SERVER_NAME 대 HTTP_HOST 문서를 참조하십시오.

    은색 총알이없는 것 같습니다. Apache가 정식 이름을 사용하도록 강제 할 때만 SERVER_NAME을 사용하여 항상 올바른 서버 이름을 얻습니다.

    따라서 여러분은 그걸 가지고 가거나 호스트 명을 화이트리스트와 대조해보아야합니다 :

    $allowed_hosts = array('foo.example.com', 'bar.example.com');
    if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
        header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
        exit;
    }
    
  2. ==============================

    2.추가 참고 사항 - 서버가 80 이외의 포트에서 실행되는 경우 (개발 / 인트라넷 시스템에서 일반적 일 수 있음) HTTP_HOST에는 포트가 포함되지만 SERVER_NAME에는 포트가 포함되지 않습니다.

    추가 참고 사항 - 서버가 80 이외의 포트에서 실행되는 경우 (개발 / 인트라넷 시스템에서 일반적 일 수 있음) HTTP_HOST에는 포트가 포함되지만 SERVER_NAME에는 포트가 포함되지 않습니다.

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

    (적어도 아파치 포트 기반의 가상 호스트에서 발견 한 것입니다)

    Mike가 아래에서 언급했듯이 HTTP_HOST에는 HTTPS를 실행할 때 443 개가 포함되지 않습니다 (테스트하지 않은 비표준 포트에서 실행중인 경우 제외).

  3. ==============================

    3.symfony가 호스트 이름을 얻기 위해 사용하는 것을 상세하게 번역 한 것입니다 (보다 직역적인 번역을위한 두 번째 예제 참조).

    symfony가 호스트 이름을 얻기 위해 사용하는 것을 상세하게 번역 한 것입니다 (보다 직역적인 번역을위한 두 번째 예제 참조).

    function getHost() {
        $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR');
        $sourceTransformations = array(
            "HTTP_X_FORWARDED_HOST" => function($value) {
                $elements = explode(',', $value);
                return trim(end($elements));
            }
        );
        $host = '';
        foreach ($possibleHostSources as $source)
        {
            if (!empty($host)) break;
            if (empty($_SERVER[$source])) continue;
            $host = $_SERVER[$source];
            if (array_key_exists($source, $sourceTransformations))
            {
                $host = $sourceTransformations[$source]($host);
            } 
        }
    
        // Remove port number from host
        $host = preg_replace('/:\d+$/', '', $host);
    
        return trim($host);
    }
    

    구식 :

    이것은 Symfony 프레임 워크에서 사용되는 최선의 방법으로 가능한 한 모든 방법으로 호스트 이름을 얻으려고 시도하는 방법을 PHP로 번역 한 것입니다.

    function get_host() {
        if ($host = $_SERVER['HTTP_X_FORWARDED_HOST'])
        {
            $elements = explode(',', $host);
    
            $host = trim(end($elements));
        }
        else
        {
            if (!$host = $_SERVER['HTTP_HOST'])
            {
                if (!$host = $_SERVER['SERVER_NAME'])
                {
                    $host = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
                }
            }
        }
    
        // Remove port number from host
        $host = preg_replace('/:\d+$/', '', $host);
    
        return trim($host);
    }
    
  4. ==============================

    4.둘 중 하나를 사용하십시오. 어쨌든 SERVER_NAME은 HTTP_HOST에서 채워지는 경우가 많으므로 둘 다 똑같이 안전합니다. 나는 일반적으로 HTTP_HOST를 사용하여 사용자가 시작한 정확한 호스트 이름을 유지합니다. 예를 들어 .com 및 .org 도메인에 동일한 사이트가있는 경우 .org에서 .com으로 다른 사람을 보내지 않으려 고합니다. 특히 .org에 로그인 토큰이 있으면 다른 도메인.

    둘 중 하나를 사용하십시오. 어쨌든 SERVER_NAME은 HTTP_HOST에서 채워지는 경우가 많으므로 둘 다 똑같이 안전합니다. 나는 일반적으로 HTTP_HOST를 사용하여 사용자가 시작한 정확한 호스트 이름을 유지합니다. 예를 들어 .com 및 .org 도메인에 동일한 사이트가있는 경우 .org에서 .com으로 다른 사람을 보내지 않으려 고합니다. 특히 .org에 로그인 토큰이 있으면 다른 도메인.

    어쨌든, 당신은 단지 당신의 webapp이 잘 알려진 도메인에 대해서만 응답 할 수 있도록 할 필요가 있습니다. 이것은 (a) Gumbo와 같은 응용 프로그램 쪽 검사를 통해 또는 (b) 알 수없는 호스트 헤더를 제공하는 요청에 응답하지 않는 원하는 도메인 이름에 가상 호스트를 사용하여 수행 할 수 있습니다.

    그 이유는 이전 이름으로 사이트에 액세스하도록 허용하면 DNS 리바운드 공격 (다른 사이트의 호스트 이름이 IP를 가리키고 사용자가 공격자의 호스트 이름으로 사이트에 액세스 한 다음 호스트 이름 공격자의 IP로 이동하여 쿠키 / 승인) 및 검색 엔진 하이재킹 (공격자가 자신의 사이트에서 자신의 호스트 이름을 가리키고 검색 엔진이이를 '최상의'기본 호스트 이름으로 간주하도록 시도)을 수행합니다.

    Pfft. 뭐, htmlspecialchars ($ string, ENT_QUOTES)로 이스케이프하지 않으면 어떤 속성에서도 사용할 수 없으므로 서버 변수에 특별한 것은 없습니다.

  5. ==============================

    5.이 둘의 주요 차이점은 $ _SERVER [ 'SERVER_NAME']은 서버 제어 변수이고 $ _SERVER [ 'HTTP_HOST']는 사용자가 제어하는 ​​값이라는 것입니다.

    이 둘의 주요 차이점은 $ _SERVER [ 'SERVER_NAME']은 서버 제어 변수이고 $ _SERVER [ 'HTTP_HOST']는 사용자가 제어하는 ​​값이라는 것입니다.

    엄지 손가락의 규칙은 사용자의 값을 결코 신뢰하지 않는 것이므로 $ _SERVER [ 'SERVER_NAME']이 (가) 더 나은 선택입니다.

    Gumbo가 지적했듯이, UseCanonicalName을 On으로 설정하지 않으면 Apache는 SERVER_NAME을 사용자 제공 값으로 구성합니다.

    편집 : 모든 사이트의 이름 기반 가상 호스트를 사용하는 경우, HTTP 호스트 헤더가 기본 사이트가 아닌 사이트에 도달하는 유일한 방법입니다.

  6. ==============================

    6.예, 승인하기 전에 $ _SERVER [ 'HTTP_HOST'] (그리고 심지어 $ _GET 및 $ _POST)를 사용하는 것이 안전합니다. 이것이 안전한 프로덕션 서버를 위해 내가하는 일입니다.

    예, 승인하기 전에 $ _SERVER [ 'HTTP_HOST'] (그리고 심지어 $ _GET 및 $ _POST)를 사용하는 것이 안전합니다. 이것이 안전한 프로덕션 서버를 위해 내가하는 일입니다.

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    $reject_request = true;
    if(array_key_exists('HTTP_HOST', $_SERVER)){
        $host_name = $_SERVER['HTTP_HOST'];
        // [ need to cater for `host:port` since some "buggy" SAPI(s) have been known to return the port too, see http://goo.gl/bFrbCO
        $strpos = strpos($host_name, ':');
        if($strpos !== false){
            $host_name = substr($host_name, $strpos);
        }
        // ]
        // [ for dynamic verification, replace this chunk with db/file/curl queries
        $reject_request = !array_key_exists($host_name, array(
            'a.com' => null,
            'a.a.com' => null,
            'b.com' => null,
            'b.b.com' => null
        ));
        // ]
    }
    if($reject_request){
        // log errors
        // display errors (optional)
        exit;
    }
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    echo 'Hello World!';
    // ...
    

    $ _SERVER [ 'HTTP_HOST']의 장점은 $ _SERVER [ 'SERVER_NAME']보다 동작이 잘 정의되어 있다는 것입니다. 콘트라스트 ➫➫ :

    와:

    $ _SERVER [ 'HTTP_HOST']와 같이 정의 된 인터페이스를 사용하면 더 많은 SAPI가 신뢰할 수있는 잘 정의 된 동작을 사용하여 SAPI를 구현합니다. (다른 것과는 달리.) 그러나 SAPI는 전적으로 SAPI에 의존합니다.

    호스트 이름을 올바르게 검색하는 방법을 이해하려면 먼저 코드 만 포함 된 서버가 네트워크에서 자신의 이름을 알 수있는 (사전 검증 필요) 방법이 없음을 이해해야합니다. 자체 이름을 제공하는 구성 요소와 인터페이스해야합니다. 다음을 통해이 작업을 수행 할 수 있습니다.

    일반적으로 로컬 (SAPI) 구성 파일을 통해 수행됩니다. 올바르게 구성했는지 확인하십시오 (예 : 아파치 ➫➫ :

  7. ==============================

    7.$ _SERVER [ 'HTTP_HOST']는 클라이언트의 헤더에 따라 다르므로 잘 모르겠습니다. 다른 방법으로 클라이언트가 요청한 도메인이 내 도메인이 아니라면 DNS와 TCP / IP 프로토콜이 올바른 대상을 가리 키기 때문에 내 사이트에 들어 가지 않습니다. 그러나 DNS, 네트워크 또는 Apache 서버를 납치 할 수 있는지 여부는 알 수 없습니다. 안전을 기하기 위해 환경에 호스트 이름을 정의하고이를 $ _SERVER [ 'HTTP_HOST']와 비교합니다.

    $ _SERVER [ 'HTTP_HOST']는 클라이언트의 헤더에 따라 다르므로 잘 모르겠습니다. 다른 방법으로 클라이언트가 요청한 도메인이 내 도메인이 아니라면 DNS와 TCP / IP 프로토콜이 올바른 대상을 가리 키기 때문에 내 사이트에 들어 가지 않습니다. 그러나 DNS, 네트워크 또는 Apache 서버를 납치 할 수 있는지 여부는 알 수 없습니다. 안전을 기하기 위해 환경에 호스트 이름을 정의하고이를 $ _SERVER [ 'HTTP_HOST']와 비교합니다.

    SetEnv MyHost domain.com을 루트의 .htaccess 파일에 추가하고 Common.php에 ths 코드를 추가하십시오.

    if (getenv('MyHost')!=$_SERVER['HTTP_HOST']) {
      header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
      exit();
    }
    

    나는이 Common.php 파일을 모든 PHP 페이지에 포함시켰다. 이 페이지는 session_start ()와 같은 각 요청에 필요한 모든 작업을 수행하며 세션 쿠키를 수정하고 post 메소드가 다른 도메인에서 온 경우 거부합니다.

  8. ==============================

    8.XSS는 $ _SERVER [ 'HTTP_HOST'], $ _SERVER [ 'SERVER_NAME'] 또는 $ _SERVER [ 'PHP_SELF']를 사용하더라도 항상 존재합니다.

    XSS는 $ _SERVER [ 'HTTP_HOST'], $ _SERVER [ 'SERVER_NAME'] 또는 $ _SERVER [ 'PHP_SELF']를 사용하더라도 항상 존재합니다.

  9. from https://stackoverflow.com/questions/1459739/php-serverhttp-host-vs-serverserver-name-am-i-understanding-the-ma by cc-by-sa and MIT license