$ _SERVER ['HTTPS']なしでHTTPSを使用しているかどうかを確認する方法


190

私はオンラインで多くのチュートリアルを見てきましたが$_SERVER['HTTPS']、サーバーがHTTPSで保護されているかどうかを確認する必要があると言っています。私の問題は、私が使用するいくつかのサーバー$_SERVER['HTTPS']で、エラーを引き起こす未定義の変数であることです。常に定義する必要があることを確認できる別の変数はありますか?

明確にするために、現在このコードを使用して、HTTPS接続であるかどうかを解決しています。

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

たぶん、$ _ SERVER ['HTTPS']が未定義のサーバーはHTTPSで実行されていますか?
フレディ

実際、そのうちの1つは私のホームWAMPサーバーです。そして、それがHTTPSで実行されているとは思わない。
タイラーカーター、

@TylerCarter、代替方法はSecureCookie を使用することです。落とし穴にも注意してください。
Pacerier 2015年

回答:


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プロトコルを介して行われなかった場合、値は「オフ」になります。(同じ動作が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上で実行されていることをどのような方法を保証していません
ブラッド・

1
次のような整数$_SERVER['SERVER_PORT'] !== 443にキャスト$_SERVER['SERVER_PORT]しなければならないという小さな問題がありました:intval($_SERVER['SERVER_PORT]) !== 443
meconroy

1
1)サーバーポートチェックはシートサーバーの追加機能であり、不要な場合は削除することをお勧めします。2)それは私の答えの緩い比較です;)
Gras Double

1
今日私が遭遇したもう1つの小さな問題。サーバーは「オフ」ではなく「オフ」を返してstrtolower($_SERVER['HTTPS']) !== 'off'いました- トリックをしました。
jhummel

116

私の解決策(標準条件[$ _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を使用してWebサーバーと通信できるため、HTTP要求の発信元プロトコルを識別するための事実上の標準です 。 org / wiki / List_of_HTTP_header_fields#Common_non-standard_request_headers


4
これは、ワニスリバースプロキシを使用する場合のソリューションです。
Reto Zahner 2013年

1
私の問題はこの解決策で解決されました。(PHP-AWS Elastic
beanstalk

これは、ロードバランサーを使用する場合のソリューションです。
Abhishek Saini 2016

どのタイプのファイルをこれに貼り付けていますか?これが.htaccessファイルにないことを想定していますか?
ジョーダン

5
これはCloudFlareが提供する無料のHTTPSでも機能します。
AnthonyVO 2017年

82

Chacha、PHPのドキュメントによれば、「スクリプトが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-正しいですが、警告はケースバイケースで対処できます。@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'))) があります:ポートチェックをまったく含みません。追加してください。:-)
ローランド

リバースプロキシの背後にある@paoloがうまくいきSetEnvIf X-Forwarded-SSL on HTTPS=onます。しかし、これはREQUEST_SCHEMEphpで使用するとうまく機能しないように思われます$_SERVER['HTTPS']
Antony Gibbs

14

これ$_SERVER['HTTPS']は未定義の場合にも機能します

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

2
$_SERVER['HTTPS']まだ定義されていないサーバーで、まだhttpsが有効になっています。どのようにそのことについて ?
ジョンマックス

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 2015

リバースプロキシを介してDockerを使用している場合に非常に役立ちます。ありがとう!
ディキリル

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 2017

5

実際の答え:[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

私はポートを追加することは良い考えではないと思います-特にビルドが異なる多くのサーバーを持っている場合。変更することを覚えておくべきことがもう1つ追加されます。ドキュメンテーションを見ると、カイザーの最後の行はかなり良いと思うので、

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ではなく空の値に変換されてしまいます。

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


3

私はこれらのパラメーターも同様に受け入れ可能であり、Webサーバーの切り替え時に誤検知がない可能性が高いです。

  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');あなたを与えるhttphttps
シャビエステベ

、作る(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
Tivie

2

$_SERVER['SERVER_PORT']SSLは通常ポート443で実行されるので確認できますが、これは確実な方法ではありません。


ただし、$ _ SERVER ['SERVER_PORT']は行います。
タイラーカーター、

2

これについてどう思いますか?

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

はいあります。empty()のみに依存している場合、「HTTPS」インデックスがない場合、PHPはエラーで終了します。
toni rmc 2016年

3
"empty()は基本的に!isset($ var)|| $ var == falseと同等の簡潔なものです" -php.net/manual/en/function.empty.php
John Magnolia

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 Webサーバーでも機能します。Chromeはv44以降、ヘッダーHTTP:1を設定しないため、HTTP_HTTPSのチェックは問題ありません。このコードがhttpsと一致しない場合は、ウェブサーバーまたはプロキシサーバーの設定が不適切であることを意味します。Apache自体がHTTPSフラグを正しく設定しますが、プロキシ(nginxなど)を使用すると問題が発生する可能性があります。nginx https仮想ホストにいくつかのヘッダーを設定する必要があります

proxy_set_header   X-HTTPS 1;

そして、いくつかのApacheモジュールを使用して、プロキシからX-HTTPSを探すことにより、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対応かどうかを判断する機会があります(1つのプロジェクトがユーザーに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を使用している可能性がある(または使用する必要がある)場合に最も信頼できる方法です。

注:(実際の可能性は低いですが)サイトに異なる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、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.