web-dev-qa-db-fra.com

Comment savoir si vous utilisez HTTPS sans $ _SERVER ['HTTPS']

J'ai vu de nombreux tutoriels en ligne qui indiquent que vous devez vérifier $_SERVER['HTTPS'] si le serveur est connecté en sécurité avec HTTPS. Mon problème est que sur certains des serveurs que j'utilise, $_SERVER['HTTPS'] est une variable non définie qui entraîne une erreur. Y at-il une autre variable que je peux vérifier et qui devrait toujours être définie?

Soyons clairs: j’utilise actuellement ce code pour résoudre s’il s’agit d’une connexion HTTPS:

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

Chacha, selon la documentation PHP: "Définissez une valeur non vide si le script a été interrogé via le protocole HTTPS." Votre déclaration if retournera donc false dans de nombreux cas où HTTPS est activé. Vous voudrez vérifier que $_SERVER['HTTPS'] existe et n'est pas vide. Dans les cas où HTTPS n'est pas défini correctement pour un serveur donné, vous pouvez essayer de vérifier si $_SERVER['SERVER_PORT'] == 443.

Cependant, notez que certains serveurs définiront également $_SERVER['HTTPS'] sur une valeur non vide. Veillez donc à vérifier également cette variable.

Référence: Documentation pour $_SERVER et $HTTP_SERVER_VARS [obsolète]

80
hobodave

Cela devrait toujours fonctionner même lorsque $_SERVER['HTTPS'] n'est pas défini:

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

Le code est compatible avec IIS.

Dans la documentation PHP.net et les commentaires de l'utilisateur :

1) Définissez une valeur non vide si le script a été interrogé via le protocole HTTPS.

2) Notez que lorsque vous utilisez ISAPI avec IIS, la valeur sera "off" si la demande n'a pas été effectuée via le protocole HTTPS. (Le même comportement a été signalé pour IIS7 sous PHP en tant qu'application Fast-CGI).

De plus, il est possible que $_SERVER['HTTPS'] ne soit pas défini sur les serveurs Apache 1.x (et les installations endommagées), même si la connexion est sécurisée. Bien que cela ne soit pas garanti, les connexions sur le port 443 utilisent, par convention , probablement avec secure sockets , d'où le contrôle de port supplémentaire.

255
Gras Double

Ma solution (car les conditions standard [$ _SERVER ['HTTPS'] == 'on'] ne fonctionnent pas sur les serveurs situés derrière un équilibreur de charge) est la suivante:

$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: norme de facto d'identification du protocole d'origine d'une requête HTTP, puisqu'un proxy inverse (équilibreur de charge) peut communiquer avec un serveur Web via HTTP même si la demande adressée au proxy inverse est HTTPS http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Common_non-standard_request_headers }

105
temuraru

Cela fonctionne aussi quand $_SERVER['HTTPS'] est indéfini 

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

Je viens d'avoir un problème où j'exécutais le serveur avec Apache mod_ssl, mais un phpinfo () et un var_dump ($ _SERVER) ont montré que PHP pense toujours que je suis sur le port 80.

Voici ma solution de contournement pour quiconque ayant le même problème ...

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

La ligne à noter est la ligne SetEnv. Avec cela en place et après un redémarrage, vous devriez avoir la variable d'environnement HTTPS dont vous avez toujours rêvé

8
thomas-peter

Si vous utilisez Apache, vous pouvez toujours compter sur

$_SERVER["REQUEST_SCHEME"]

vérifier le schéma de l'URL demandée. Mais, comme mentionné dans d'autres réponses, il est prudent de vérifier d'autres paramètres avant de supposer que SSL est réellement utilisé.

7
Ed de Almeida

La vraie réponse: prêt pour copier-coller dans un script [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 est maintenant correct et prêt à être utilisé; exemple $site=$pv_URIprotocol.$_SERVER["SERVER_NAME"]. Naturellement, la chaîne pourrait également être remplacée par TRUE et FALSE. PV signifie PortalPress Variable puisqu'il s'agit d'un copier-coller direct qui fonctionnera toujours. Cette pièce peut être utilisée dans un script de production.

5

Créer ma propre fonction en lisant tous les posts précédents:

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

Je trouve ces paramètres également acceptables et, plus que probablement, ne comportent pas de faux positifs lors du changement de serveur 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*/}
    
3
Werezywolf

La seule méthode fiable est celle décrite par 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://");

Considérez les points suivants: Vous utilisez nginx avec fastcgi, par défaut (debian, ubuntu) fastgi_params contient la directive:

fastcgi_param HTTPS $ https;

si vous n'utilisez PAS SSL, il est traduit en tant que valeur vide, pas "off", pas 0 et vous êtes condamné.

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

3
Galvani

Je ne pense pas que l'ajout d'un port soit une bonne idée - spécialement lorsque vous avez plusieurs serveurs avec différentes versions. cela ajoute juste une dernière chose à retenir pour changer. En regardant doc, je pense que la dernière ligne de kaisers est assez bonne, de sorte que:

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

semble parfaitement suffisant.

3
sp3c1

Vous pouvez vérifier $_SERVER['SERVER_PORT'] car SSL fonctionne normalement sur le port 443, mais cela n’est pas infaillible.

2
pix0r

Que pensez-vous de cela?

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

Sur mon serveur (Ubuntu 14.10, Apache 2.4, php 5.5), la variable $_SERVER['HTTPS'] n'est pas définie lorsque le script php est chargé via https. Je ne sais pas ce qui ne va pas. Mais les lignes suivantes dans le fichier .htaccess résolvent ce problème:

RewriteEngine on

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

Le plus court chemin que j'utilise:

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

Si, si https est utilisé, alors $ secure_connection est vrai.

2
Markus Zeller

juste pour l’intérêt, chrome Canary au moment envoie 

HTTPS : 1

au serveur, et en fonction de la configuration du serveur, vous pouvez obtenir les informations suivantes:

HTTPS : 1, on

Cela a cassé notre application parce que nous étions en train de tester, ce qui n’est évidemment pas le cas. À l’heure actuelle, seul le chrome Canary semble le faire, mais il est intéressant de noter que les produits du canari tombent généralement dans le chrome "normal" peu de temps après.

1
John Smith

Voici une fonction réutilisable que j'utilise depuis un moment. HTH.

Remarque: la valeur de HTTPS_PORT (qui est une constante personnalisée dans mon code) peut varier en fonction de votre environnement, par exemple 443 ou 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
crmpicco
$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;

Le code vérifie tout ce qui est possible et fonctionne également sur le serveur Web IIS. Chrome depuis la v44 ne définit pas l'en-tête HTTP: 1, donc vérifier HTTP_HTTPS est correct. Si ce code ne correspond pas à https, cela signifie que votre serveur Web ou serveur proxy est mal configuré. Apache lui-même définit correctement l'indicateur HTTPS, mais des problèmes peuvent survenir lorsque vous utilisez un proxy (par exemple, nginx). Vous devez définir un en-tête dans l'hôte virtuel nginx https.

proxy_set_header   X-HTTPS 1;

et utilisez un module Apache pour définir correctement l'indicateur HTTPS en recherchant X-HTTPS à partir d'un proxy. Recherchez mod_fakessl, mod_rpaf, etc.

1
mikep

Si vous utilisez nginx comme système d’équilibrage de charge, vérifiez $ _SERVER ['HTTP_HTTPS'] == 1 autre vérification échouera pour SSL.

1
basis

J'ai l'occasion d'aller plus loin et de déterminer si le site auquel je me connecte est compatible SSL (un projet demande à l'utilisateur son URL et nous devons vérifier qu'il a installé notre pack API sur un site http ou https).

Voici la fonction que j'utilise - en gros, appelez simplement l'URL via cURL pour voir si https fonctionne!

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

C’est le moyen le plus fiable que j’ai trouvé de découvrir non seulement SI vous utilisez https (comme le demande la question), mais aussi si vous POUVEZ (ou même DEVRAIT) utiliser https. 

NOTE: il est possible (bien que ce ne soit pas vraiment probable ...) qu'un site puisse avoir différentes pages http et https (donc si on vous dit d'utiliser http, vous n'avez peut-être pas besoin de changer ..) La grande majorité des sites sont les mêmes, et devraient probablement vous rediriger eux-mêmes, mais cette vérification supplémentaire a son utilisation (certainement, comme je l'ai dit, dans le projet où l'utilisateur entre leurs informations de site et que vous voulez vous assurer du côté serveur)

0
CFP Support

J'ai utilisé la suggestion principale ici et je me suis énervé face à la "notification PHP" dans les journaux lorsque HTTPS n'était pas défini. Vous pouvez l'éviter en utilisant le opérateur null-coalescing "??":

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

(Note: non disponible avant php v7)

0
garafajon

Voici comment je trouve résoudre ce

$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
Fhulufhelo Mokhomi

J'ajouterais un filtre global pour m'assurer que tout ce que je vérifie est correct.

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
Rodrigo Manara

Si vous utilisez l'équilibreur de charge d'Incapsula, vous devez utiliser une règle pour générer un en-tête personnalisé pour votre serveur. J'ai créé un en-tête HTTP_X_FORWARDED_PROTO égal à "http" si le port est défini sur 80 et "https" s'il est égal à 443.

0
Nadav