$ _SERVER없이 HTTPS를 사용하고 있는지 확인하는 방법 [ 'HTTPS']


190

$_SERVER['HTTPS']서버가 HTTPS로 안전하게 연결 되어 있는지 확인해야한다고 알려주는 많은 자습서를 온라인에서 보았습니다 . 내 문제는 내가 사용하는 일부 서버 $_SERVER['HTTPS']에서 정의되지 않은 변수이며 오류가 발생한다는 것입니다. 확인할 수있는 다른 변수가 항상 정의되어 있습니까?

분명히하기 위해 현재이 코드를 사용하여 HTTPS 연결인지 확인하고 있습니다.

if(isset($_SERVER['HTTPS'])) {
    if ($_SERVER['HTTPS'] == "on") {
        $secure_connection = true;
    }
}

우연히 $ _SERVER [ 'HTTPS']가 정의되지 않은 서버가 HTTPS에서 실행되고 있습니까?
Freddy

실제로, 그들 중 하나는 내 집 WAMP 서버입니다. 그리고 그것이 HTTPS에서 실행되고 있다고 생각하지 않습니다.
Tyler Carter

@TylerCarter, 다른 방법은 Secure쿠키 를 사용하는 것 입니다. 그래도 조심해야합니다.
Pacerier

답변:


280

$_SERVER['HTTPS']정의되지 않은 경우에도 항상 작동합니다 .

function isSecure() {
  return
    (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
    || $_SERVER['SERVER_PORT'] == 443;
}

이 코드는 IIS와 호환됩니다.

로부터 PHP.net 문서 및 사용자 의견 :

1) 스크립트가 HTTPS 프로토콜을 통해 쿼리 된 경우 비어 있지 않은 값으로 설정하십시오.

2) IIS에서 ISAPI를 사용할 때 HTTPS 프로토콜을 통해 요청하지 않은 경우 값이 "off"가됩니다. PHP를 Fast-CGI 응용 프로그램으로 실행하는 IIS7에 대해 동일한 동작이보고되었습니다.

또한 Apache 1.x 서버 (및 손상된 설치)가 $_SERVER['HTTPS']안전하게 연결되어 있어도 정의 되지 않았을 수 있습니다 . 보장되지는 않지만 포트 443의 연결은 일반적으로 보안 소켓을 사용 하므로 추가 포트 확인이 가능합니다.

추가 참고 사항 : 클라이언트와 서버 사이에로드 밸런서가있는 경우이 코드는 클라이언트와로드 밸런서 간의 연결을 테스트하지 않고로드 밸런서와 서버 간의 연결을 테스트합니다. 이전 연결을 테스트하려면 HTTP_X_FORWARDED_PROTO헤더를 사용하여 테스트해야 하지만 훨씬 더 복잡합니다. 이 답변 아래의 최신 의견을 참조하십시오 .


50
Nb : 포트 443은 연결의 암호화를 보증하지 않습니다
ErichBSchulz

2
@DavidRodrigues 사실이 아닙니다. 원하는 포트를 통해 HTTP / HTTPS를 사용할 수 있습니다. getservbyname()는 실제가 아니라 단지 참조 일 뿐이며, 어떤 식 으로든 HTTPS가 포트 443을 통해 실행되고 있다는 것을 보증하지 않습니다.
Brad

1
나는 다음 과 같이 정수 $_SERVER['SERVER_PORT'] !== 443로 캐스팅 해야한다는 작은 문제가 있었습니다 $_SERVER['SERVER_PORT].intval($_SERVER['SERVER_PORT]) !== 443
meconroy

1
1) 서버 포트 확인은 불완전한 서버에 추가로 필요하지 않은 경우 제거하는 것이 가장 좋습니다. 2) 내 대답에서 느슨한 비교입니다.)
Gras Double

1
오늘 내가 겪은 또 하나의 작은 문제. 서버가 'off'가 아닌 'OFF'를 반환했습니다 strtolower($_SERVER['HTTPS']) !== 'off'. 트릭을 수행했습니다.
jhummel

117

내 솔루션 (표준 조건 [$ _SERVER [ 'HTTPS'] == 'on']이로드 밸런서 뒤에있는 서버에서 작동하지 않기 때문에)은 다음과 같습니다.

$isSecure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
    $isSecure = true;
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
    $isSecure = true;
}
$REQUEST_PROTOCOL = $isSecure ? 'https' : 'http';

HTTP_X_FORWARDED_PROTO : 리버스 프록시 (로드 밸런서)가 HTTPS http : //en.wikipedia 인 경우에도 리버스 프록시 (로드 밸런서)가 HTTP를 사용하여 웹 서버와 통신 할 수 있으므로 HTTP 요청의 원래 프로토콜을 식별하기위한 사실상의 표준입니다 . org / wiki / List_of_HTTP_header_fields # Common_non-standard_request_headers


4
니스 리버스 프록시를 사용하는 경우 솔루션입니다.
Reto Zahner

1
이 솔루션으로 문제가 해결되었습니다. (PHP-AWS Elastic Beanstalk)
user4826347

로드 밸런서를 사용하는 경우 솔루션입니다.
Abhishek Saini

어떤 파일 형식을 사용하고 있습니까? 이것이 .htaccess 파일에 없다고 가정하고 있습니까?
Jordan

5
이는 CloudFlare에서 제공하는 무료 HTTPS에서도 작동합니다.
AnthonyVO

82

PHP 문서에 따라 Chacha : "스크립트가 HTTPS 프로토콜을 통해 쿼리 된 경우 비어 있지 않은 값으로 설정하십시오." 따라서 HTTPS가 실제로 켜져있는 경우 많은 경우 if 문이 false를 반환합니다. $_SERVER['HTTPS']존재하고 비어 있지 않은지 확인하고 싶을 것 입니다. 특정 서버에 대해 HTTPS가 올바르게 설정되지 않은 경우를 확인하십시오 $_SERVER['SERVER_PORT'] == 443.

그러나 일부 서버는 $_SERVER['HTTPS']비어 있지 않은 값으로 설정 되므로이 변수도 확인하십시오.

참조 : 문서 $_SERVER$HTTP_SERVER_VARS[더 이상 사용되지 않음]


12
use $ _SERVER [ 'SERVER_PORT']는 까다로울 수 있습니다. 예를 들어, ispconfig는 포트 81을 보안 포트로 사용하므로 443이 ssl의 "기본"포트라고 할 수 있습니다.
Gabriel Sosa

@Gabriel Sosa-사실이지만주의 사항에 따라주의를 기울일 수 있습니다. @hobodave의 답변이 가장 효과적입니다.
Tim Post

리버스 프록시 뒤에서는 작동하지 않습니다. 확인 HTTP_X_FORWARDED_PROTO하거나 고려할 수도 HTTP_X_FORWARDED_SSL있습니다.
paolo

1
나는 최후의 수단은 포트 번호 여야한다는 것에 동의하므로 여기에 내 확인이 (((isset($_SERVER['HTTPS'])) && (strtolower($_SERVER['HTTPS']) == 'on')) || ((isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) && (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'))) 있습니다. 자유롭게 추가하십시오. :-)
Roland

리버스 프록시 뒤의 @paolo SetEnvIf X-Forwarded-SSL on HTTPS=on가 트릭을 수행합니다. 그러나이하지 않습니다 작업 REQUEST_SCHEMEPHP에서 결과로는 사용에 더 나은 것 같다$_SERVER['HTTPS']
안토니 깁스에게

14

이것은 $_SERVER['HTTPS']정의되지 않은 경우에도 작동합니다

if( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443 ){
    //enable secure connection
}

2
$_SERVER['HTTPS']아직 정의되지 않은 일부 서버 는 https를 사용합니다. 어떻게에 대한 ?
John Max

1
@JohnMax SERVER_PORT는 정의되지 않은 문제를 해결하기 위해 항상 정의됩니다HTTPS
Thamaraiselvam

11

Apache mod_ssl을 사용하여 서버를 실행하는 데 문제가 있었지만 phpinfo () 및 var_dump ($ _SERVER)는 PHP가 여전히 포트 80에 있다고 생각합니다.

다음은 동일한 문제가있는 사람을위한 해결 방법입니다 ....

<VirtualHost *:443>
  SetEnv HTTPS on
  DocumentRoot /var/www/vhost/scratch/content
  ServerName scratch.example.com
</VirtualHost>

주목할만한 줄은 SetEnv 줄입니다. 이를 사용하고 다시 시작한 후에는 항상 꿈꿔 왔던 HTTPS 환경 변수가 있어야합니다


5
HTTPS가 제대로 작동하는지 확인하십시오. 그렇지 않은 경우 서버가 사용자에게 거짓말을합니다.
Brad Koch

또한 이것이 작동하려면 SetEnv 모듈이 필요합니다. 기본적으로 활성화되어 있지만 서버 관리자가 비활성화 할 수있는 것을 절대 알 수 없습니다.
toon81

리버스 프록시를 통해 도커에있는 경우 매우 유용합니다. 감사!
dikirill

8

모든 이전 게시물을 읽지 않고 내 기능을 수행하십시오.

public static function isHttps()
{
    if (array_key_exists("HTTPS", $_SERVER) && 'on' === $_SERVER["HTTPS"]) {
        return true;
    }
    if (array_key_exists("SERVER_PORT", $_SERVER) && 443 === (int)$_SERVER["SERVER_PORT"]) {
        return true;
    }
    if (array_key_exists("HTTP_X_FORWARDED_SSL", $_SERVER) && 'on' === $_SERVER["HTTP_X_FORWARDED_SSL"]) {
        return true;
    }
    if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER) && 'https' === $_SERVER["HTTP_X_FORWARDED_PROTO"]) {
        return true;
    }
    return false;
}

7

Apache를 사용하는 경우 항상 신뢰할 수 있습니다

$_SERVER["REQUEST_SCHEME"]

요청 된 URL의 체계를 확인합니다. 그러나 다른 답변에서 언급했듯이 SSL이 실제로 사용되고 있다고 가정하기 전에 다른 매개 변수를 확인하는 것이 좋습니다.


XAMPP에서는 작동하지만 centos / apache2 + PHP에서는 작동하지 않으므로 신뢰할 수 없습니다.
Firas Abd Alrahman

5

REAL 답변 : [config] 스크립트에 복사하여 붙여 넣기 준비

/* configuration settings; X=edit may 10th '11 */
$pv_sslport=443; /* for it might be different, as also Gabriel Sosa stated */
$pv_serverport=80; /* X */
$pv_servername="mysite.com"; /* X */

/* X appended after correction by Michael Kopinsky */
if(!isset($_SERVER["SERVER_NAME"]) || !$_SERVER["SERVER_NAME"]) {
    if(!isset($_ENV["SERVER_NAME"])) {
        getenv("SERVER_NAME");
        // Set to env server_name
        $_SERVER["SERVER_NAME"]=$_ENV["SERVER_NAME"];
    }
}
if(!$_SERVER["SERVER_NAME"]) (
    /* X server name still empty? ... you might set $_SERVER["SERVER_NAME"]=$pv_servername; */
}

if(!isset($_SERVER["SERVER_PORT"]) || !$_SERVER["SERVER_PORT"]) {
    if(!isset($_ENV["SERVER_PORT"])) {
        getenv("SERVER_PORT");
        $_SERVER["SERVER_PORT"]=$_ENV["SERVER_PORT"];
    }
}
if(!$_SERVER["SERVER_PORT"]) (
    /* X server port still empty? ... you might set $_SERVER["SERVER_PORT"]=$pv_serverport; */
}

$pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") :  (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");

$pv_URIprotocol이제 정확하고 사용할 준비가되었습니다. 예 $site=$pv_URIprotocol.$_SERVER["SERVER_NAME"]. 당연히 문자열을 TRUE 및 FALSE로 바꿀 수도 있습니다. PV는 PortalPress Variable의 약자로, 항상 작동하는 직접 복사 붙여 넣기입니다. 이 조각은 프로덕션 스크립트에서 사용할 수 있습니다.


3

포트를 추가하는 것이 좋은 생각이라고 생각하지 않습니다. 특히 빌드가 다른 서버가 많을 때 특히 그렇습니다. 변경해야 할 사항이 하나 더 추가됩니다. 문서를 보면 카이저의 마지막 줄이 꽤 좋다고 생각합니다.

if(!empty($_SERVER["HTTPS"]))
  if($_SERVER["HTTPS"]!=="off")
    return 1; //https
  else
    return 0; //http
else
  return 0; //http

완벽하게 보입니다.


3

신뢰할 수있는 유일한 방법은 Igor M이 설명한 방법입니다.

$pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") :  (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");

다음을 고려하십시오 : 기본적으로 fastcgi와 함께 nginx를 사용하고 있습니다. 기본적으로 (debian, ubuntu) fastgi_params contains 지시문 :

fastcgi_param HTTPS $ https;

SSL을 사용하지 않으면 0이 아닌 'off'가 아닌 빈 값으로 변환되어 파산됩니다.

http://unpec.blogspot.cz/2013/01/nette-nginx-php-fpm-redirect.html


3

이러한 매개 변수도 수용 가능하며 웹 서버를 전환 할 때 잘못된 긍정이 없을 가능성이 높습니다.

  1. $ _SERVER [ 'HTTPS_KEYSIZE']
  2. $ _SERVER [ 'HTTPS_SECRETKEYSIZE']
  3. $ _SERVER [ 'HTTPS_SERVER_ISSUER']
  4. $ _SERVER [ 'HTTPS_SERVER_SUBJECT']

    if($_SERVER['HTTPS_KEYSIZE'] != NULL){/*do foobar*/}

로드 밸런서 / 프록시를 사용한 HTTPS 사용에 대해서는 아무 것도 알려주지 않습니다.
Brad

3

내가 사용하는 가장 짧은 방법 :

$secure_connection = !empty($_SERVER['HTTPS']);

https가 사용되면 $ secure_connection이 true입니다.


echo (!empty($_SERVER['HTTPS'])?'https':'http');당신을 제공 http하거나https
사비 에스테

, 확인(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
Tivie

2

$_SERVER['SERVER_PORT']SSL이 일반적으로 포트 443에서 실행되는지 확인할 수 있지만 이는 완벽하지는 않습니다.


그러나 $ _SERVER [ 'SERVER_PORT']는 그렇지 않습니다.
Tyler Carter

2

이것에 대해서 어떻게 생각하니?

if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
    $scheme = 'https';
else
    $scheme = 'http';

그렇습니다. empty ()에만 의존하는 경우 'HTTPS'인덱스가 없으면 PHP가 오류와 함께 종료됩니다.
toni rmc

3
- "! || 간결한 당량으로는 isset ($ var에) 본질적으로) ($ VAR == 거짓 비울" php.net/manual/en/function.empty.php
존 목련

2
네 말이 맞아 재미있었습니다. 변수가 존재하지 않으면 항상 empty ()가 실패한다고 생각했습니다.
toni rmc

2

내 서버 (Ubuntu 14.10, Apache 2.4, php 5.5)에서 $_SERVER['HTTPS']PHP 스크립트가 https를 통해로드되면 변수 가 설정되지 않습니다. 나는 무엇이 잘못되었는지 모른다. 그러나 .htaccess파일의 다음 줄은 이 문제를 해결합니다.

RewriteEngine on

RewriteCond %{HTTPS} =on [NC] 
RewriteRule .* - [E=HTTPS:on,NE]

1

여기 내가 오랫동안 사용했던 재사용 가능한 기능이 있습니다. HTH.

참고 : 내 코드에서 사용자 정의 상수 인 HTTPS_PORT 값은 환경에 따라 다를 수 있습니다 (예 : 443 또는 81).

/**
 * Determine if this is a secure HTTPS connection
 * 
 * @return  bool    True if it is a secure HTTPS connection, otherwise false.
 */
function isSSL()
{
    if (isset($_SERVER['HTTPS'])) {
        if ($_SERVER['HTTPS'] == 1) {
            return true;
        } elseif ($_SERVER['HTTPS'] == 'on') {
            return true;
        }
    } elseif ($_SERVER['SERVER_PORT'] == HTTPS_PORT) {
        return true;
    }

    return false;
}

1

관심을 끌기 위해 순간에 크롬 카나리아가 보냅니다.

HTTPS : 1

서버 구성 방법에 따라 다음을 다시 얻을 수 있음을 의미 할 수 있습니다.

HTTPS : 1, on

켜져 있으면 테스트 중이기 때문에 응용 프로그램이 중단되었으므로 분명히 그렇지 않습니다. 현재 크롬 카나리아 만이 작업을 수행하는 것으로 보이지만 카나리아의 항목은 일반적으로 "정상"크롬에 잠시 후에 도착한다는 점에 주목할 가치가 있습니다.


1

로드 밸런싱 시스템 검사로 nginx를 사용하면 $ _SERVER [ 'HTTP_HTTPS'] == 1 ssl에 대한 다른 검사가 실패합니다.


1
$secure_connection = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] != 'off') || $_SERVER['REQUEST_SCHEME'] == 'https' || $_SERVER['SERVER_PORT'] == 443) ? true : false;

코드가 가능한 것을 확인하고 IIS 웹 서버에서도 작동합니다. v44부터 Chrome은 헤더 HTTP : 1을 설정하지 않으므로 HTTP_HTTPS를 확인하는 것이 좋습니다. 이 코드가 https와 일치하지 않으면 웹 서버 또는 프록시 서버가 제대로 구성되지 않은 것입니다. Apache 자체는 HTTPS 플래그를 올바르게 설정하지만 프록시 (예 : nginx)를 사용할 때 문제가 발생할 수 있습니다. nginx https 가상 호스트에 헤더를 설정해야합니다

proxy_set_header   X-HTTPS 1;

프록시에서 X-HTTPS를 찾아서 일부 Apache 모듈을 사용하여 HTTPS 플래그를 올바르게 설정하십시오. mod_fakessl, mod_rpaf 등을 검색하십시오.


0

Incapsula의로드 밸런서를 사용하는 경우 IRule을 사용하여 서버의 사용자 지정 헤더를 생성해야합니다. 포트가 80으로 설정된 경우 "http"및 443과 같은 경우 "https"와 동일한 HTTP_X_FORWARDED_PROTO 헤더를 작성했습니다.


0

확인하는 모든 것이 올바른지 확인하기 위해 전역 필터를 추가합니다.

function isSSL() {

    $https = filter_input(INPUT_SERVER, 'HTTPS');
    $port = filter_input(INPUT_SERVER, 'SERVER_PORT');
    if ($https) {

        if ($https == 1) {
            return true;
        } elseif ($https == 'on') {
            return true;
        }
    } elseif ($port == '443') {
        return true;
    }

    return false;
}

0

한 걸음 더 나아가서 연결하려는 사이트가 SSL을 지원하는지 확인할 수 있습니다 (한 프로젝트는 사용자에게 URL을 요청하고 http 또는 https 사이트에 API 팩을 설치했는지 확인해야합니다).

내가 사용하는 기능은 다음과 같습니다. 기본적으로 cURL을 통해 URL을 호출하여 https가 작동하는지 확인하십시오!

function hasSSL($url) 
{
    // take the URL down to the domain name
    $domain = parse_url($url, PHP_URL_HOST);
    $ch = curl_init('https://' . $domain);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); //its a  HEAD
    curl_setopt($ch, CURLOPT_NOBODY, true);          // no body
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  // in case of redirects
    curl_setopt($ch, CURLOPT_VERBOSE, 0); //turn on if debugging
    curl_setopt($ch, CURLOPT_HEADER, 1);     //head only wanted
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);    // we dont want to wait forever
    curl_exec($ch);
    $header = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($header === 200) {
        return true;
    }
    return false;
}

이것은 https를 사용하고 있는지 (질문과 같이) 확인하는 것뿐만 아니라 https를 사용해야 할 때 (또는 SHOULD) 확인하는 가장 신뢰할 수있는 방법입니다.

참고 : 사이트에 http 및 https 페이지가 다를 수 있습니다 (실제로는 아니지만 ...). 따라서 http를 사용하라는 메시지가 표시되면 변경할 필요가 없습니다 .. 대부분의 사이트 동일하고 아마도 자신을 다시 라우팅해야하지만이 추가 검사는 용도가 있습니다 (확실히 말하면 사용자가 사이트 정보를 입력하고 서버 측에서 확인하려는 프로젝트에서 말했듯이)


0

이것이 내가 이것을 찾는 방법입니다.

$https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0 ||
        !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
            strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;

return ($https) ? 'https://' : 'http://';

0

여기에서 주요 제안을 사용하고 HTTPS가 설정되지 않은 경우 로그의 "PHP Notice"에 짜증이났습니다. 널 병합 연산자 "??" 를 사용하면이를 피할 수 있습니다 .

if( ($_SERVER['HTTPS'] ?? 'off') == 'off' ) {
    // redirect
}

(참고 : PHP v7 이전에는 사용할 수 없습니다)


-7

hobodave의 게시물에 따르면 : "HTTPS 프로토콜을 통해 스크립트를 쿼리 한 경우 비어 있지 않은 값으로 설정하십시오."

if (!empty($_SERVER['HTTPS']))
{
    $secure_connection = true;
}

만들 그것(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
Tivie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.