Comment puis-je forcer les utilisateurs à accéder à ma page via HTTPS au lieu de HTTP?

137

Je n'ai qu'une seule page à laquelle je veux forcer l'accès en tant que page HTTPS (PHP sur Apache). Comment faire cela sans que tout le répertoire nécessite HTTPS? Ou, si vous soumettez un formulaire à une page HTTPS à partir d'une page HTTP, l'envoie-t-il par HTTPS au lieu de HTTP?

Voici mon exemple:

http://www.example.com/some-page.php

Je souhaite qu'il soit uniquement accessible via:

https://www.example.com/some-page.php

Bien sûr, je peux mettre tous les liens vers cette page pointés vers la version HTTPS, mais cela n'empêche pas un imbécile d'y accéder volontairement via HTTP ...

Une chose que je pensais était de mettre une redirection dans l'en-tête du fichier PHP pour vérifier qu'ils accèdent à la version HTTPS:

if($_SERVER["SCRIPT_URI"] == "http://www.example.com/some-page.php"){
  header('Location: https://www.example.com/some-page.php');
}

Mais cela ne peut pas être la bonne façon, n'est-ce pas?

Wiki
la source
3
Y a-t-il une raison pour laquelle vous n'avez pas simplement besoin de SSL pour toutes les pages?
Le Tahaan

Réponses:

177

La façon dont je l'ai fait avant est fondamentalement comme ce que vous avez écrit, mais n'a pas de valeurs codées en dur:

if ($ _ SERVER ["HTTPS"]! = "on")
{
    header ("Emplacement: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    sortie();
}
Adam Rosenfield
la source
15
Vous avez oublié d'appeler exit () pour vous assurer que le script se ferme après la redirection. J'emballe généralement cela dans une fonction appelée requireSSL (). Je peux appeler ceci en haut de n'importe quelle page que je souhaite chiffrer.
Jesse Weigert le
31
Modifiez le if to be (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")pour corriger les notifications PHP.
dave1010
Les $_SERVER[]variables ne sont-elles pas modifiables / vulnérables à l'intervention des utilisateurs?
Arian Faurtosh
Source @ArianFaurtosh?
John
3
@ArianFaurtosh certains sont extraits des en-têtes des clients, comme HTTP_X_FORWARDED, et peuvent être manipulés, mais d'autres aiment HTTPSou SERVER_PORTsont définis directement à partir du serveur Web et devraient généralement être sûrs.
Mahn
46

Vous pouvez le faire avec une directive et mod_rewrite sur Apache:

<Location /buyCrap.php>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Location>

Vous pouvez rendre la localisation plus intelligente au fil du temps en utilisant des expressions régulières si vous le souhaitez.

thebigjc
la source
6
Où mettriez-vous cela? Fichier .htaccess?
1
REQUEST_URI n'inclut pas la "chaîne de requête" (comme? Page = 1 & id = 41 etc.)? C'est ce que dit la documentation Apache ... Donc, si j'essaye d'accéder à site.com/index.php?page=1&id=12 je serai redirigé vers site.com/index.php
Rolf
2
Depuis la documentation apache: REQUEST_URI Le composant de chemin de l'URI demandé, tel que "/index.html". Ceci exclut notamment la chaîne de requête qui est disponible comme sa propre variable nommée QUERY_STRING. Vous devrez donc ajouter QUERY_STRING après REQUEST_URI
Rolf
2
Vous devez également ajouter le flage [R] après cela pour le rediriger
Rolf
40

Vous devez forcer le client à toujours demander HTTPS avec les en- têtes HTTP Strict Transport Security (HSTS):

// Use HTTP Strict Transport Security to force client to use secure connections only
$use_sts = true;

// iis sets HTTPS to 'off' for non-SSL requests
if ($use_sts && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
    header('Strict-Transport-Security: max-age=31536000');
} elseif ($use_sts) {
    header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
    // we are in cleartext at the moment, prevent further execution and output
    die();
}

Veuillez noter que HSTS est pris en charge dans la plupart des navigateurs modernes, mais pas universel. Ainsi, la logique ci-dessus redirige manuellement l'utilisateur indépendamment de la prise en charge s'il se retrouve sur HTTP, puis définit l'en-tête HSTS de sorte que les demandes des clients supplémentaires doivent être redirigées par le navigateur si possible.

Jacob Swartwood
la source
Je suis surpris que non des autres réponses incluent cet en-tête, c'est assez important ... un piège pour combiner les deux?
keisar
Non ... vous pouvez certainement définir cet en-tête de toute façon si vous voulez toujours HTTPS. Il est juste en quelque sorte redondant de le définir avant et après la redirection. J'ai également modifié ma réponse ci-dessus pour expliquer plus précisément la compatibilité.
Jacob Swartwood
1
(Rédaction du commentaire original) Je n'ai pas remarqué l'exigence spécifique de "juste une page". HSTS s'appliquera à toutes les pages; ma réponse est techniquement incorrecte.
Jacob Swartwood
4
FYI, la norme RFC 6797 section 7.2 dit "Un hôte HSTS NE DOIT PAS inclure le champ d'en-tête STS dans les réponses HTTP acheminées sur un transport non sécurisé." donc pas besoin de l'envoyer lorsque la requête est normale http, il faut l'ignorer si le navigateur suit le standard.
Frank Forte
1
@mark s'il y a un MITM et que votre site Web n'a pas cet en-tête, vous pouvez autoriser une session comprise à aller sur http et les gens entrer leurs détails et ils ne le remarqueront probablement pas et une redirection n'aidera pas (l'homme en le milieu se connectera au site via https et le présentera comme http). L'utilisation de cet en-tête forcera HTTPS côté client. Ceci est particulièrement important en raison de la récente vulnérabilité de sécurité WiFi WPA2.
Rudiger
19

Je viens de créer un fichier .htaccess et j'ai ajouté:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Facile !

MatHatrik
la source
9
// Force HTTPS for security
if($_SERVER["HTTPS"] != "on") {
    $pageURL = "Location: https://";
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
    }
    header($pageURL);
}
Jeff
la source
8

J'ai dû faire quelque chose comme ça lors de l'exécution derrière un équilibreur de charge. Pointe du chapeau https://stackoverflow.com/a/16076965/766172

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

function requireHTTPS() {
    if (!isSecure()) {
        header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], TRUE, 301);
        exit;
    }
}
syvex
la source
6

La manière PHP:

$is_https=false;
if (isset($_SERVER['HTTPS'])) $is_https=$_SERVER['HTTPS'];
if ($is_https !== "on")
{
    header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
    exit(1);
}

La manière Apache mod_rewrite:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Geai
la source
Je préfère la méthode PHP car il y a des cas où je souhaite ignorer l'exigence de SSL. Par exemple, l'accès local aux API et à des choses comme la configuration automatique de Mozilla Thunderbird, etc.
Jay
La méthode PHP fonctionne parfaitement pour moi, hautement recommandée.
Moxet le
5

http://www.besthostratings.com/articles/force-ssl-htaccess.html

Parfois, vous devrez peut-être vous assurer que l'utilisateur navigue sur votre site via une connexion sécurisée. Un moyen simple de toujours rediriger l'utilisateur vers une connexion sécurisée (https: //) peut être réalisé avec un fichier .htaccess contenant les lignes suivantes:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

Veuillez noter que le .htaccess doit être situé dans le dossier principal du site Web.

Si vous souhaitez forcer HTTPS pour un dossier particulier, vous pouvez utiliser:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteCond %{REQUEST_URI} somefolder 
RewriteRule ^(.*)$ https://www.domain.com/somefolder/$1 [R,L]

Le fichier .htaccess doit être placé dans le dossier où vous devez forcer HTTPS.

itsazzad
la source
5

Ok .. Maintenant, il y a des tonnes de trucs à ce sujet maintenant mais personne ne répond vraiment à la question "Sécurisé". Pour moi, il est ridicule d'utiliser quelque chose qui n'est pas sûr.

À moins que vous ne l'utilisiez comme appât.

La propagation de $ _SERVER peut être modifiée à la volonté de quelqu'un qui sait comment.

De plus, comme Sazzad Tushar Khan et thebigjc l'ont déclaré, vous pouvez également utiliser httaccess pour le faire et il y a beaucoup de réponses ici qui le contiennent.

Il suffit d'ajouter:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://example.com/$1 [R,L]

à la fin de ce que vous avez dans votre .httaccess et c'est tout.

Nous ne sommes toujours pas aussi sûrs que possible avec ces 2 outils.

Le reste est simple. S'il manque des attributs, c'est-à-dire ...

if(empty($_SERVER["HTTPS"])){ // SOMETHING IS FISHY
}

if(strstr($_SERVER['HTTP_HOST'],"mywebsite.com") === FALSE){// Something is FISHY
}


Disons également que vous avez mis à jour votre fichier httaccess et que vous vérifiez:

if($_SERVER["HTTPS"] !== "on"){// Something is fishy
}

Il y a beaucoup plus de variables que vous pouvez vérifier, par exemple ..

HOST_URI (S'il y a des atributs statiques à vérifier)

HTTP_USER_AGENT (Même session différentes valeurs)

Donc, tout ce que je dis, c'est de ne pas se contenter de l'un ou de l'autre lorsque la réponse réside dans une combinaison.

Pour plus d'informations sur la réécriture des accès https, consultez la documentation-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Quelques piles ici -> Forcer SSL / https à l'aide de .htaccess et mod_rewrite
et
obtenir l'URL complète du page courante (PHP)
pour en nommer un couple.

JSG
la source
2
mais maintenant je reçois l'erreur suivante: ERR_TOO_MANY_REDIRECTS. Comment puis-je réparer ça?
Pathros
3

Utilisez $_SERVER['HTTPS']pour dire si c'est SSL , et redirigez vers le bon endroit sinon.

Et rappelez-vous, la page qui affiche le formulaire n'a pas besoin d'être alimentée via HTTPS, c'est l'URL de retour qui en a le plus besoin.

Edit : oui, comme indiqué ci-dessous, il est préférable d'avoir l'ensemble du processus en HTTPS. C'est beaucoup plus rassurant - je faisais remarquer que le message est la partie la plus critique. De plus, vous devez veiller à ce que tous les cookies soient définis pour être sécurisés, de sorte qu'ils ne seront envoyés que via SSL. La solution mod_rewrite est également très astucieuse, je l'ai utilisée pour sécuriser de nombreuses applications sur mon propre site Web.

DGM
la source
Il est vrai que le formulaire lui-même n'a pas besoin d'être https, bien que ce soit une bonne idée pour la majorité des personnes qui ne le savent pas. S'ils sont sur le point de soumettre le formulaire et remarquent que l'icône de verrouillage n'est pas là, ils peuvent supposer à tort que le formulaire n'est pas sécurisé.
Graeme Perrow
1
@Graeme: de plus, personne ne peut être sûr que le formulaire sera envoyé via https. Le formulaire entier (affiché via http) peut être un faux, soumis à un site en clair inconnu ou http. Https n'est pas seulement une question de cryptage, il authentifie également le serveur.
Olaf Kock le
3

utiliser htaccess:

#if domain has www. and not https://
  RewriteCond %{HTTPS} =off [NC]
  RewriteCond %{HTTP_HOST} ^(?i:www+\.+[^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]

#if domain has not www.
  RewriteCond %{HTTP_HOST} ^([^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]
siavash bagheri
la source
1

Ne mélangez pas HTTP et HTTPS sur la même page. Si vous avez une page de formulaire qui est servie via HTTP, je vais être nerveux à propos de la soumission de données - je ne peux pas voir si la soumission passe par HTTPS ou HTTP sans faire une vue de la source et la rechercher.

Servir le formulaire sur HTTPS avec le lien de soumission n'est pas un changement si lourd pour l'avantage.

JBB
la source
1

Si vous utilisez Apache ou quelque chose comme LiteSpeed, qui prend en charge les fichiers .htaccess, vous pouvez effectuer les opérations suivantes. Si vous ne disposez pas déjà d'un fichier .htaccess, vous devez créer un nouveau fichier .htaccess dans votre répertoire racine (généralement où se trouve votre index.php). Ajoutez maintenant ces lignes comme premières règles de réécriture dans votre .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Vous n'avez besoin de l'instruction "RewriteEngine On" qu'une seule fois dans votre .htaccess pour toutes les règles de réécriture, donc si vous l'avez déjà, copiez simplement la deuxième et la troisième ligne.

J'espère que ça aide.

Antonio
la source
C'est ce qui a fonctionné pour moi et ce que j'utilise dans mes propres scripts sur un Framework de type Zend 2 - je ne comprends pas le vote négatif.
Antonio
Peut-être avez-vous été critiqué parce que la réponse est pratiquement la même que celle de @MatHatrik qui a été publiée plus d'un an plus tôt?
Wilt
1

Utiliser ceci n'est PAS suffisant:

if($_SERVER["HTTPS"] != "on")
{
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

Si vous avez du contenu http (comme une source d'image http externe), le navigateur détectera une menace possible. Assurez-vous donc que tous vos ref et src dans votre code sont https

webmaster bourax
la source
1

J'ai traversé de nombreuses solutions pour vérifier le statut de $ _SERVER [HTTPS] mais il semble que ce n'est pas fiable car parfois il ne se met pas sur on, off, etc. provoquant la redirection de boucle interne du script.

Voici la solution la plus fiable si votre serveur prend en charge $ _SERVER [SCRIPT_URI]

if (stripos(substr($_SERVER[SCRIPT_URI], 0, 5), "https") === false) {
    header("location:https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
    echo "<meta http-equiv='refresh' content='0; url=https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]'>";
    exit;
}

Veuillez noter que selon votre installation, votre serveur peut ne pas prendre en charge $ _SERVER [SCRIPT_URI] mais si c'est le cas, c'est le meilleur script à utiliser.

Vous pouvez vérifier ici: Pourquoi certaines installations PHP ont $ _SERVER ['SCRIPT_URI'] et d'autres pas

Tarik
la source
1

Pour ceux qui utilisent IIS, l'ajout de cette ligne dans le web.config aidera:

<httpProtocol>
    <customHeaders>
        <add name="Strict-Transport-Security" value="max-age=31536000"/>
    </customHeaders>
</httpProtocol>
<rewrite>
    <rules>
        <rule name="HTTP to HTTPS redirect" stopProcessing="true">
              <match url="(.*)" />
              <conditions>
                 <add input="{HTTPS}" pattern="off" ignoreCase="true" />
              </conditions>
              <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
         </rule>
    </rules>
</rewrite>

Un fichier d'exemple complet

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Strict-Transport-Security" value="max-age=31536000"/>
             </customHeaders>
        </httpProtocol>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                      <match url="(.*)" />
                      <conditions>
                         <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                      </conditions>
                      <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
                 </rule>
            </rules>
       </rewrite>
   </system.webServer>
</configuration>
Tschallacka
la source
La question concerne spécifiquement Apache, pas IIS.
Quentin
1
A) son apache non étiqueté. Apache est cité entre guillemets. B) c'est une question générique qui n'a rien à voir avec Apache en général. Il s'applique à plusieurs serveurs Web prenant en charge PHP
Tschallacka
0

Vous ne devriez pas pour des raisons de sécurité. Surtout si les cookies sont en jeu ici. Cela vous laisse grand ouvert aux attaques de relecture basées sur les cookies.

Dans tous les cas, vous devez utiliser les règles de contrôle Apache pour le régler.

Ensuite, vous pouvez tester l'activation de HTTPS et rediriger si nécessaire si nécessaire.

Vous devez rediriger vers la page de paiement uniquement en utilisant un FORM POST (pas de get), et les accès à la page sans POST doivent être redirigés vers les autres pages. (Cela attrapera les gens qui sautent à chaud.)

http://joseph.randomnetworks.com/archives/2004/07/22/redirect-to-ssl-using-apaches-htaccess/

Est-ce un bon point de départ, excuses pour ne pas en fournir plus. Mais tu devrais vraiment tout pousser via SSL.

C'est trop protecteur, mais au moins vous avez moins de soucis.

Kent Fredric
la source
0

peut-être que celui-ci peut vous aider, c'est comme ça que j'ai fait pour mon site, ça marche comme un charme:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

if (!strstr($protocol, 'https')){
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}
Mongars Héouais
la source
0

Si vous souhaitez utiliser PHP pour ce faire, cette méthode a très bien fonctionné pour moi:


<?php

if(!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != "on") {
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"], true, 301);
    //Prevent the rest of the script from executing.
    exit;
}
?>

Il vérifie la variable HTTPS dans le tableau superglobal $ _SERVER pour voir si elle est égale à «on». Si la variable n'est pas égale à on.

écureuil
la source
-1

J'ai utilisé ce script et il fonctionne bien sur le site.

if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off"){
    $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    enter code hereheader('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $redirect);
    exit();
}
Esteban Gallego
la source
-2
<?php 
// Require https
if ($_SERVER['HTTPS'] != "on") {
    $url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    header("Location: $url");
    exit;
}
?>

C'est simple.

Épeler
la source