$ _SERVER ['HTTPS'] olmadan HTTPS kullanıp kullanmadığınızı nasıl öğrenebilirsiniz?


190

$_SERVER['HTTPS']Sunucu bağlantı HTTPS ile güvenli olup olmadığını kontrol etmeniz gerektiğini söyleyen çevrimiçi birçok öğretici gördüm . Benim sorunum kullandığım bazı sunucularda $_SERVER['HTTPS']bir hata ile sonuçlanan tanımsız bir değişken olmasıdır. Her zaman tanımlanması gereken kontrol edebileceğim başka bir değişken var mı?

Sadece açık olmak gerekirse, şu anda bir HTTPS bağlantısı olup olmadığını çözmek için bu kodu kullanıyorum:

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

Herhangi bir olasılıkla, $ _SERVER ['HTTPS'] 'in tanımsız olduğu sunucular HTTPS üzerinde çalışıyor mu?
Freddy

Aslında bunlardan biri benim ev WAMP sunucum. Ve HTTPS'de çalıştığına inanmıyorum.
Tyler Carter

@TylerCarter, Alternatif bir yöntem Secureçerez kullanmaktır . Olsa gotchas dikkatli olun.
Pacerier

Yanıtlar:


280

Bu $_SERVER['HTTPS'], tanımlanmamış olsa bile her zaman çalışmalıdır :

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

Kod IIS ile uyumludur.

Gönderen PHP.net dokümantasyon ve kullanıcı yorumları :

1) Komut dosyası HTTPS protokolü aracılığıyla sorgulandıysa boş olmayan bir değere ayarlayın.

2) ISAPI'yi IIS ile kullanırken, istek HTTPS protokolü üzerinden yapılmazsa değerin "kapalı" olacağını unutmayın. (PHP'nin Fast-CGI uygulaması olarak çalıştığı IIS7 için de aynı davranış bildirilmiştir).

Ayrıca, $_SERVER['HTTPS']güvenli bir şekilde bağlansa bile Apache 1.x sunucuları (ve bozuk kurulumlar) tanımlanmamış olabilir . Her ne kadar garanti edilmese de, 443 numaralı bağlantı noktasındaki bağlantılar, kural olarak , muhtemelen güvenli yuvalar kullanır , bu nedenle ek bağlantı noktası denetimi yapılır.

Ek not: istemci ile sunucunuz arasında bir yük dengeleyici varsa, bu kod istemci ile yük dengeleyici arasındaki bağlantıyı değil, yük dengeleyici ile sunucunuz arasındaki bağlantıyı test eder. Önceki bağlantıyı test etmek için, HTTP_X_FORWARDED_PROTObaşlığı kullanarak test etmeniz gerekir , ancak yapılması çok daha karmaşıktır; bkz son açıklamalarının bu cevap aşağıda.


50
Nb: 443 numaralı bağlantı noktası, bağlantının şifreli olduğunu garanti etmez
ErichBSchulz

2
@DavidRodrigues Bu doğru değil. HTTP / HTTPS'yi istediğiniz bağlantı noktası üzerinden kullanabilirsiniz. getservbyname()yalnızca bir referanstır, gerçeklik değildir ve HTTPS'nin 443 numaralı bağlantı noktası üzerinde çalıştığını hiçbir şekilde garanti etmez.
Brad

1
Ben böyle bir tamsayı $_SERVER['SERVER_PORT'] !== 443döküm vardı küçük bir sorun vardı $_SERVER['SERVER_PORT]:intval($_SERVER['SERVER_PORT]) !== 443
meconroy

1
1) Sunucu bağlantı noktası denetimi, lazımlık sunucuları için fazladan bir değerdir, en iyisi gerekli değilse kaldırmaktır. 2) Cevabımda gevşek bir karşılaştırma olduğuna dikkat edin;)
Gras Double

1
Bugün bir küçük sorun daha yaşadım. Sunucu 'OFF' değil 'off' dönüyordu - strtolower($_SERVER['HTTPS']) !== 'off'hile yaptı.
jhummel

117

Çözümüm (standart koşullar [$ _SERVER ['HTTPS'] == 'on'] bir yük dengeleyicinin arkasındaki sunucularda çalışmadığı için:

$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: bir tersine proxy (yük dengeleyici), ters proxy'ye istek HTTPS http: //en.wikipedia olsa bile HTTP kullanarak bir web sunucusuyla iletişim kurabileceğinden, bir HTTP isteğinin kaynak protokolünü tanımlamak için fiili bir standarttır . org / wiki / List_of_HTTP_header_fields # Common_non-standard_request_headers


4
Vernik ters proxy kullanıyorsanız bu çözümdür.
Reto Zahner

1
Sorunum bu çözümle çözüldü. (PHP - AWS Elastik fasulye
sapı

Yük dengeleyicileri kullanıyorsanız çözüm budur.
Abhishek Saini

Bunu ne tür bir dosyaya yapıştırıyorsunuz? Bunun .htaccess dosyasında olmadığını varsayıyorum?
Ürdün

5
Bu aynı zamanda CloudFlare tarafından sağlanan ücretsiz HTTPS için de geçerlidir.
AnthonyVO

82

Chacha, PHP belgelerine göre: "Komut dosyası HTTPS protokolü aracılığıyla sorgulandıysa boş olmayan bir değere ayarlayın." Yani if ​​ifadeniz HTTPS'nin gerçekten açık olduğu birçok durumda false değerini döndürür. Var olduğunu $_SERVER['HTTPS']ve boş olmadığını doğrulamak isteyeceksiniz . HTTPS'nin belirli bir sunucu için doğru ayarlanmadığı durumlarda, olup olmadığını kontrol etmeyi deneyebilirsiniz $_SERVER['SERVER_PORT'] == 443.

Ancak bazı sunucuların da $_SERVER['HTTPS']boş olmayan bir değere ayarlanacağını unutmayın , bu nedenle bu değişkeni de kontrol ettiğinizden emin olun.

Referans: ve [kullanımdan kaldırıldı] dokümanları$_SERVER$HTTP_SERVER_VARS


12
$ _SERVER ['SERVER_PORT'] kullanın zor olabilir ... örneğin ispconfig 81 numaralı bağlantı noktasını güvenli bağlantı noktası olarak kullanır, bu nedenle 443'ün ssl için "varsayılan" bağlantı noktası olduğunu varsayalım.
Gabriel Sosa

@Gabriel Sosa - Doğru, ancak uyarılar vaka bazında ele alınabilir. @ hobodave'nin cevabı en çok işe yarayacak.
Tim Post

Bunun ters bir proxy arkasında çalışmayacağını unutmayın. Bir kontrol etmek düşünebilir HTTP_X_FORWARDED_PROTOveya HTTP_X_FORWARDED_SSLyanı.
paolo

1
Kabul ediyorum son çare liman numarası olmalı, bu yüzden burada benim kontrol: (((isset($_SERVER['HTTPS'])) && (strtolower($_SERVER['HTTPS']) == 'on')) || ((isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) && (strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'))) hangi liman denetimi hiç içermez. Eklemek için çekinmeyin. :-)
Roland

@paolo ters bir proxy arkasında SetEnvIf X-Forwarded-SSL on HTTPS=onhile yapacak. Ama bu REQUEST_SCHEMEphp sonuç olarak işe yaramazsa kullanmak daha iyi görünüyor$_SERVER['HTTPS']
Antony Gibbs

14

Bu $_SERVER['HTTPS']tanımsız olduğunda da çalışır

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

2
$_SERVER['HTTPS']Henüz tanımlanmayan ve https'nin etkin olduğu bazı sunuculardır . Peki ya bu ?
John Max

1
@JohnMax SERVER_PORTher zaman tanımlanmamış sorunu çözer tanımlanırHTTPS
Thamaraiselvam

11

Ben sadece Apache mod_ssl kullanarak sunucu çalıştıran bir sorun vardı, henüz bir phpinfo () ve bir var_dump ($ _SERVER) PHP hala bağlantı noktası 80 olduğunu düşündüğünü gösterdi.

İşte aynı sorunu olan herkes için benim geçici çözüm ....

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

Dikkate değer çizgi SetEnv çizgisidir. Bu durumdayken ve yeniden başlattıktan sonra, her zaman hayal ettiğiniz HTTPS ortam değişkenine sahip olmalısınız


5
HTTPS'nin gerçekten çalıştığından emin olun; sunucunun size yalan söylemesini sağlar.
Brad Koch

Ayrıca bunun çalışması için SetEnv modülüne ihtiyacınız vardır. Varsayılan olarak etkindir, ancak bir sunucu yöneticisinin neyi devre dışı bırakabileceğini asla bilemezsiniz.
toon81

Ters proxy üzerinden docker üzerinde olması durumunda çok yararlı. Teşekkürler!
dikirill

8

Önceki tüm mesajları okumaktan kendi fonksiyonumu yapmak:

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 kullanıyorsanız her zaman güvenebilirsiniz

$_SERVER["REQUEST_SCHEME"]

istenen URL'nin şemasını doğrulamak için. Ancak, diğer yanıtlarda da belirtildiği gibi, SSL'nin gerçekten kullanıldığını varsaymadan önce diğer parametreleri doğrulamak ihtiyatlıdır.


XAMPP üzerinde çalışıyor ancak centos / apache2 + PHP üzerinde çalışmıyor ... bu yüzden güvenilir değil.
Firas Abd Alrahman

5

GERÇEK cevap: bir [config] komut dosyasına kopyalayıp yapıştırmaya hazır

/* 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_URIprotocolartık doğru ve kullanıma hazır; örnek $site=$pv_URIprotocol.$_SERVER["SERVER_NAME"]. Doğal olarak, dize TRUE ve FALSE ile de değiştirilebilir. PV, her zaman çalışacak doğrudan bir kopyala yapıştır olduğu için PortalPress Değişkeni anlamına gelir. Bu parça bir üretim senaryosunda kullanılabilir.


3

Bir bağlantı noktası eklemenin iyi bir fikir olduğunu düşünmüyorum - özellikle farklı yapılara sahip birçok sunucunuz olduğunda. bu sadece değişmeyi hatırlamak için bir şey daha ekler. doc's bakarak kaiser son satır oldukça iyi olduğunu düşünüyorum, böylece:

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

yeterince mükemmel görünüyor.


3

Tek güvenilir yöntem Igor M. tarafından tarif edilen yöntemdir.

$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://");

Aşağıdakileri göz önünde bulundurun: nginx'i fastcgi ile kullanıyorsunuz, varsayılan olarak (debian, ubuntu) fastgi_params yönergesi içerir:

fastcgi_param HTTPS $ https;

SSL kullanmıyorsanız, 0 değil, 'kapalı' değil boş değer olarak çevrilir ve mahkum olursunuz.

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


3

Bu parametreleri de kabul edilebilir buluyorum ve muhtemelen web sunucularını değiştirirken yanlış pozitifler yok.

  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*/}

Bu, yük dengeleyici / proxy ile HTTPS kullanımı hakkında hiçbir şey söylemez.
Brad

3

Kullandığım en kısa yol:

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

Https kullanılıyorsa, $ secure_connection doğrudur.


echo (!empty($_SERVER['HTTPS'])?'https':'http');size httpveyahttps
Xavi Esteve

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

2

$_SERVER['SERVER_PORT']SSL'nin 443 numaralı bağlantı noktasında normal olarak çalıştığını kontrol edebilirsiniz , ancak bu kusursuz değildir.


Ancak $ _SERVER ['SERVER_PORT'] bunu yapar.
Tyler Carter

2

Bunun hakkında ne düşünüyorsun?

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

Evet var. Yalnızca empty () yöntemine güveniyorsanız, 'HTTPS' dizini yoksa PHP hatalı olarak çıkacaktır.
toni rmc

3
"empty () aslında! isset ($ var) || $ var == false" ile özlü bir eşdeğerdir - php.net/manual/en/function.empty.php
John Magnolia

2
Haklısın. Komik olanı özledim. Değişken yoksa hep boş () başarısız olur diye düşündüm.
toni rmc

2

Sunucumda (Ubuntu 14.10, Apache 2.4, php 5.5) değişkeni $_SERVER['HTTPS'], php betiği https yoluyla yüklendiğinde ayarlanmadı. Neyin yanlış olduğunu bilmiyorum. Ancak .htaccessdosyadaki aşağıdaki satırlar bu sorunu giderir:

RewriteEngine on

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

1

İşte bir süredir kullandığım yeniden kullanılabilir bir fonksiyon. HTH.

Not: HTTPS_PORT (kodumda özel bir sabit olan) değeri, uygulamanıza göre değişebilir, örneğin 443 veya 81 olabilir.

/**
 * 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

sadece ilgi için, şu anda krom kanarya gönderir

HTTPS : 1

ve sunucunun nasıl yapılandırıldığına bağlı olarak aşağıdakileri geri alabileceğiniz anlamına gelebilir

HTTPS : 1, on

Bu bizim başvurumuzu kırdı çünkü biz açık değilse, biz test edildi. Şu anda, sadece krom kanarya bunu yapıyor gibi görünüyor, ancak kanaryadan gelen şeylerin genellikle kısa bir süre sonra "normal" kromun içine girdiğini belirtmek gerekir.


1

Eğer yük dengeleme sistemi olarak nginx kullanırsanız $ _SERVER ['HTTP_HTTPS'] == 1 diğer kontroller SSL için başarısız olur.


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;

Kod mümkün olan her şeyi kontrol ediyor ve IIS web sunucusunda da çalışıyor. Chrome, v44, HTTP: 1 üstbilgisini ayarlamadığından, HTTP_HTTPS'yi kontrol etmek TAMAM. Bu kod https ile eşleşmezse, web sunucunuzun veya proxy sunucunuzun kötü yapılandırılmış olduğu anlamına gelir. Apache'nin kendisi HTTPS bayrağını doğru bir şekilde ayarlar, ancak proxy (ör. Nginx) kullanırken sorun olabilir. Nginx https sanal ana bilgisayarında bir başlık ayarlamanız gerekir

proxy_set_header   X-HTTPS 1;

ve proxy'den X-HTTPS arayarak HTTPS bayrağını doğru ayarlamak için bazı Apache modüllerini kullanın. Mod_fakessl, mod_rpaf vb. İçin arama yapın.


0

Incapsula'nın yük dengeleyicisini kullanıyorsanız, sunucunuz için özel bir başlık oluşturmak için bir IRule kullanmanız gerekir. Bağlantı noktası 80 olarak ayarlanmışsa "http" ve 443'e eşitse "https" olan bir HTTP_X_FORWARDED_PROTO üstbilgisi oluşturdum.


0

Kontrol ettiğim her şeyin doğru olduğundan emin olmak için küresel bir filtre eklerdim;

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

Bir adım daha ileri gidip bağlandığım sitenin SSL uyumlu olup olmadığını belirlemek için bir fırsatım var (bir proje kullanıcıdan URL'sini soruyor ve API paketimizi bir http veya https sitesine yüklediklerini doğrulamamız gerekiyor).

İşte kullandığım işlev - temel olarak, https'nin çalışıp çalışmadığını görmek için URL'yi cURL yoluyla çağırmanız yeterlidir!

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;
}

Bu, sadece https (soru sorulduğu gibi) kullanıyorsanız değil, aynı zamanda https kullanıyor olabilirseniz (hatta SHOULD) da bulmak için bulduğum en güvenilir yoldur.

NOT: Bir sitenin farklı http ve https sayfalarına sahip olması mümkündür (gerçekten de olası değildir ...) (bu nedenle http'yi kullanmanız istenirse, belki de değiştirmeniz gerekmez ..) Sitelerin büyük çoğunluğu aynıdır ve muhtemelen sizi yeniden yönlendirmelidir, ancak bu ek kontrolün kullanımı vardır (kesinlikle dediğim gibi, kullanıcının site bilgilerini girdiği ve sunucu tarafından emin olmak istediğiniz projede)


0

Bunu bu şekilde çözerim

$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

Burada ana öneriyi kullandım ve HTTPS ayarlanmadığında günlüklerde "PHP Bildirimi" rahatsız oldum. Null birleştirme operatörü "??" kullanarak bunu önleyebilirsiniz :

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

(Not: php v7'den önce kullanılamaz)


-7

Hobodave'nin gönderisine göre: "Komut dosyası HTTPS protokolü aracılığıyla sorgulandıysa boş olmayan bir değere ayarlayın."

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

yapmak(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
Tivie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.