Wie kann ich Benutzer zwingen, über HTTPS anstelle von HTTP auf meine Seite zuzugreifen?

137

Ich habe nur eine Seite, auf die ich als HTTPS-Seite (PHP unter Apache) zugreifen möchte. Wie mache ich das, ohne dass das gesamte Verzeichnis HTTPS erfordert? Wenn Sie ein Formular von einer HTTP-Seite an eine HTTPS-Seite senden, wird es dann über HTTPS anstelle von HTTP gesendet?

Hier ist mein Beispiel:

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

Ich möchte, dass nur über Folgendes zugegriffen werden kann:

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

Natürlich kann ich alle Links zu dieser Seite, die auf die HTTPS-Version verweisen, einfügen, aber das hindert keinen Dummkopf daran, absichtlich über HTTP darauf zuzugreifen ...

Ich dachte, ich würde eine Umleitung in den Header der PHP-Datei einfügen, um zu überprüfen, ob sie auf die HTTPS-Version zugreifen:

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

Aber das kann doch nicht der richtige Weg sein, oder?

Wiki
quelle
Mögliches Duplikat von Force SSL / https mit .htaccess und mod_rewrite
Trilarion
3
Gibt es einen Grund, warum Sie nicht nur SSL für alle Seiten benötigen?
Der Tahaan

Antworten:

177

Die Art und Weise, wie ich es zuvor gemacht habe, ist im Grunde wie das, was Sie geschrieben haben, hat aber keine fest codierten Werte:

if ($ _ SERVER ["HTTPS"]! = "on")
{
    Header ("Speicherort: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    Ausfahrt();
}}
Adam Rosenfield
quelle
15
Sie haben vergessen, exit () aufzurufen, um sicherzustellen, dass das Skript nach der Umleitung beendet wird. Normalerweise verpacke ich das in eine Funktion namens requireSSL (). Ich kann dies oben auf jeder Seite aufrufen, die ich verschlüsseln möchte.
Jesse Weigert
31
Ändern Sie das if (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on"), um PHP-Hinweise zu korrigieren.
Dave1010
Sind $_SERVER[]Variablen nicht veränderbar / anfällig für Benutzereingriffe?
Arian Faurtosh
@ArianFaurtosh Quelle?
John
3
@ArianFaurtosh Einige werden aus Client-Headern extrahiert HTTP_X_FORWARDEDund können manipuliert werden, andere mögen HTTPSoder SERVER_PORTwerden direkt vom Webserver festgelegt und sollten normalerweise sicher sein.
Mahn
46

Sie könnten es mit einer Direktive und mod_rewrite auf Apache tun:

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

Sie können den Standort im Laufe der Zeit mit regulären Ausdrücken intelligenter gestalten, wenn Sie möchten.

thebigjc
quelle
6
Wo würdest du das hinstellen? .htaccess-Datei?
1
Enthält REQUEST_URI nicht die "Abfragezeichenfolge" (wie? Page = 1 & id = 41 usw.)? Das steht in der Apache-Dokumentation ... Wenn ich also versuche, auf site.com/index.php?page=1&id=12 zuzugreifen, werde ich site.com/index.php
Rolf
2
Aus der Apache-Dokumentation: REQUEST_URI Die Pfadkomponente des angeforderten URI, z. B. "/index.html". Dies schließt insbesondere die Abfragezeichenfolge aus, die als eigene Variable mit dem Namen QUERY_STRING verfügbar ist. Sie müssen also QUERY_STRING nach REQUEST_URI
Rolf
2
Sie müssen auch die [R] -Flage danach hinzufügen, damit sie umgeleitet wird
Rolf
40

Sie sollten den Client zwingen , HTTPS immer mit HSTS-Headern ( HTTP Strict Transport Security ) anzufordern:

// 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();
}

Bitte beachten Sie, dass HSTS in den meisten modernen Browsern unterstützt wird, jedoch nicht universell. Daher leitet die obige Logik den Benutzer unabhängig von der Unterstützung manuell um, wenn er auf HTTP landet, und setzt dann den HSTS-Header so, dass weitere Clientanforderungen nach Möglichkeit vom Browser umgeleitet werden.

Jacob Swartwood
quelle
Ich bin überrascht, dass keine der anderen Antworten diesen Header enthält. Es ist ziemlich wichtig. Gibt es eine Falle für die Kombination der beiden?
Keisar
Nein ... Sie könnten diesen Header definitiv festlegen, wenn Sie immer HTTPS möchten. Es ist nur redundant, es vor und nach der Umleitung festzulegen. Ich habe auch meine Antwort oben geändert, um die Kompatibilität genauer zu erklären.
Jacob Swartwood
1
(Originalkommentar redigieren) Ich habe die spezielle Anforderung von "nur eine Seite" nicht bemerkt. HSTS gilt für alle Seiten; Meine Antwort ist technisch falsch.
Jacob Swartwood
4
Zu Ihrer Information, der Standard-RFC 6797, Abschnitt 7.2, besagt: "Ein HSTS-Host darf das STS-Headerfeld NICHT in HTTP-Antworten enthalten, die über einen nicht sicheren Transport übermittelt werden." Damit es nicht gesendet werden muss, wenn die Anforderung regulär http ist, sollte es ignoriert werden, wenn der Browser dem Standard folgt.
Frank Forte
1
@mark Wenn es ein MITM gibt und Ihre Website diesen Header nicht hat, können Sie einer zusammengesetzten Sitzung erlauben, zu http zu gehen, und die Leute geben ihre Details ein, und sie werden es wahrscheinlich nicht bemerken und eine Weiterleitung wird nicht helfen (der Mann in Die Mitte stellt über https eine Verbindung zur Site her und präsentiert sie als http). Die Verwendung dieses Headers erzwingt HTTPS auf der Clientseite. Dies ist besonders wichtig aufgrund der jüngsten Sicherheitslücke in WPA2 WiFi.
Rüdiger
19

Ich habe gerade eine .htaccess-Datei erstellt und hinzugefügt:

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

Einfach!

MatHatrik
quelle
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
quelle
8

Musste so etwas tun, wenn man hinter einem Load Balancer läuft. Hutspitze 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
quelle
6

Der PHP-Weg:

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

Der Apache mod_rewrite Weg:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Jay
quelle
Ich bevorzuge die PHP-Methode, da es Fälle gibt, in denen ich die Anforderung für SSL überschreiben möchte. Zum Beispiel lokaler Zugriff auf APIs und Dinge wie die automatische
Jay
Die PHP-Methode funktioniert perfekt für mich, sehr zu empfehlen.
Moxet
5

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

Manchmal müssen Sie möglicherweise sicherstellen, dass der Benutzer Ihre Website über eine sichere Verbindung durchsucht. Eine einfache Möglichkeit, den Benutzer immer zur sicheren Verbindung umzuleiten (https: //), kann mit einer .htaccess-Datei erreicht werden, die die folgenden Zeilen enthält:

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

Bitte beachten Sie, dass sich der .htaccess im Hauptordner der Website befinden sollte.

Wenn Sie HTTPS für einen bestimmten Ordner erzwingen möchten, können Sie Folgendes verwenden:

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

Die .htaccess-Datei sollte in dem Ordner abgelegt werden, in dem Sie HTTPS erzwingen müssen.

itsazzad
quelle
5

Ok .. Jetzt gibt es Unmengen von Dingen, aber niemand beantwortet die Frage "Sicher" wirklich. Für mich ist es lächerlich, etwas zu verwenden, das unsicher ist.

Es sei denn, Sie verwenden es als Köder.

Die Weitergabe von $ _SERVER kann nach dem Willen von jemandem geändert werden, der weiß, wie.

Auch wie Sazzad Tushar Khan und der Thebigjc sagten, können Sie auch httaccess verwenden, um dies zu tun, und es gibt hier viele Antworten, die es enthalten.

Einfach hinzufügen:

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

bis zum Ende dessen, was Sie in Ihrem .httaccess haben und das ist es.

Trotzdem sind wir mit diesen beiden Tools nicht so sicher wie möglich.

Der Rest ist einfach. Wenn Attribute fehlen, z.

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

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


Angenommen, Sie haben Ihre httaccess-Datei aktualisiert und überprüfen Folgendes:

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

Es gibt viel mehr Variablen, die Sie überprüfen können, z.

HOST_URI (Wenn es statische Attribute gibt, die überprüft werden müssen)

HTTP_USER_AGENT (Gleiche Sitzung unterschiedliche Werte)

Alles, was ich sage, ist, sich nicht nur mit dem einen oder anderen zufrieden zu geben, wenn die Antwort in einer Kombination liegt.

Weitere Informationen zum Umschreiben von httaccess finden Sie in den Dokumenten-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Einige Stapel hier -> Erzwingen Sie SSL / https mit .htaccess und mod_rewrite
und
rufen Sie die vollständige URL des ab aktuelle Seite (PHP)
, um ein paar zu nennen.

JSG
quelle
2
aber jetzt bekomme ich folgenden fehler : ERR_TOO_MANY_REDIRECTS. Wie behebe ich das?
Pathros
3

Verwenden $_SERVER['HTTPS']Sie diese Option , um festzustellen , ob es sich um SSL handelt , und leiten Sie an die richtige Stelle weiter, wenn dies nicht der Fall ist.

Und denken Sie daran, dass die Seite, auf der das Formular angezeigt wird, nicht über HTTPS eingegeben werden muss. Es ist die Post-Back-URL, die es am meisten benötigt.

Bearbeiten : Ja, wie unten ausgeführt, ist es am besten, den gesamten Prozess in HTTPS zu haben. Es ist viel beruhigender - ich habe darauf hingewiesen, dass der Beitrag der kritischste Teil ist. Außerdem müssen Sie darauf achten, dass Cookies so eingestellt sind, dass sie sicher sind, sodass sie nur über SSL gesendet werden. Die mod_rewrite-Lösung ist auch sehr geschickt. Ich habe sie verwendet, um viele Anwendungen auf meiner eigenen Website zu sichern.

DGM
quelle
Es ist wahr, dass das Formular selbst nicht https sein muss, obwohl es eine gute Idee für die Mehrheit der Leute ist, die dies nicht wissen. Wenn sie das Formular senden möchten und feststellen, dass das Schlosssymbol nicht vorhanden ist, gehen sie möglicherweise fälschlicherweise davon aus, dass das Formular unsicher ist.
Graeme Perrow
1
@Graeme: Außerdem kann niemand sicher sein, dass das Formular jemals über https gesendet wird. Das gesamte Formular (angezeigt über http) ist möglicherweise eine Fälschung, die an eine unbekannte oder http-Klartext-Site gesendet wird. Bei HTTP geht es nicht nur um Verschlüsselung, sondern auch um die Authentifizierung des Servers.
Olaf Kock
3

Verwenden Sie 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
quelle
1

Mischen Sie HTTP und HTTPS nicht auf derselben Seite. Wenn Sie eine Formularseite haben, die über HTTP bereitgestellt wird, bin ich nervös, wenn Daten übermittelt werden. Ich kann nicht sehen, ob die Übermittlung über HTTPS oder HTTP erfolgt, ohne eine Ansichtsquelle zu erstellen und danach zu suchen.

Das Bereitstellen des Formulars über HTTPS zusammen mit dem Submit-Link ist keine so große Änderung für den Vorteil.

JBB
quelle
1

Wenn Sie Apache oder etwas wie LiteSpeed ​​verwenden, das .htaccess-Dateien unterstützt, können Sie Folgendes tun. Wenn Sie noch keine .htaccess-Datei haben, sollten Sie eine neue .htaccess-Datei in Ihrem Stammverzeichnis erstellen (normalerweise dort, wo sich Ihre index.php befindet). Fügen Sie nun diese Zeilen als erste Umschreiberegeln in Ihren .htaccess ein:

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

Sie benötigen die Anweisung "RewriteEngine On" nur einmal in Ihrem .htaccess für alle Umschreiberegeln. Wenn Sie sie bereits haben, kopieren Sie einfach die zweite und dritte Zeile.

Ich hoffe das hilft.

Antonio
quelle
Dies ist, was für mich funktioniert hat und was ich in meinen eigenen Skripten auf einem Zend 2-ähnlichen Framework verwende - ich verstehe die Abwertung nicht.
Antonio
Vielleicht hast du downvoted , weil die Antwort praktisch die gleiche wie diese von @MatHatrik , die mehr als ein Jahr zuvor geschrieben wurde?
Wilt
1

Dies zu verwenden ist NICHT genug:

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

Wenn Sie über http-Inhalte verfügen (z. B. eine externe http-Bildquelle), erkennt der Browser eine mögliche Bedrohung. Stellen Sie also sicher, dass alle Ihre ref und src in Ihrem Code https sind

Bourax Webmaster
quelle
1

Ich habe viele Lösungen mit der Überprüfung des Status von $ _SERVER [HTTPS] durchlaufen, aber es scheint nicht zuverlässig zu sein, da es manchmal nicht aktiviert oder aktiviert, deaktiviert usw. wird und das Skript eine interne Schleifenumleitung verursacht.

Hier ist die zuverlässigste Lösung, wenn Ihr Server $ _SERVER [SCRIPT_URI] unterstützt.

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

Beachten Sie, dass Ihr Server abhängig von Ihrer Installation möglicherweise $ _SERVER [SCRIPT_URI] nicht unterstützt. Wenn dies jedoch der Fall ist, ist dies das bessere Skript.

Sie können hier überprüfen: Warum haben einige PHP-Installationen $ _SERVER ['SCRIPT_URI'] und andere nicht

Tarik
quelle
1

Für Benutzer von IIS hilft das Hinzufügen dieser Zeile in der web.config:

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

Eine vollständige Beispieldatei

<?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
quelle
Die Frage bezieht sich speziell auf Apache, nicht auf IIS.
Quentin
1
A) Es ist kein Apache markiert. Apache wird zwischen Anführungszeichen angezeigt. B) Es ist eine generische Frage, die im Allgemeinen nichts mit Apache zu tun hat. Es ist anwendbar auf mehrere PHP unterstützende Webserver
Tschallacka
0

Sie sollten aus Sicherheitsgründen nicht. Besonders wenn hier Cookies im Spiel sind. Sie sind offen für Cookie-basierte Wiederholungsangriffe.

In beiden Fällen sollten Sie Apache-Steuerregeln verwenden, um die Einstellungen zu optimieren.

Anschließend können Sie testen, ob HTTPS aktiviert ist, und bei Bedarf nach Bedarf umleiten.

Sie sollten nur mit einem FORM POST (no get) auf die Bezahlseite umleiten, und der Zugriff auf die Seite ohne POST sollte auf die anderen Seiten zurückgeleitet werden. (Dies wird die Leute nur beim Springen erwischen.)

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

Ist ein guter Anfang, entschuldigt sich dafür, dass Sie nicht mehr zur Verfügung gestellt haben. Aber du solltest es wirklich alles über SSL schieben.

Es ist übermäßig schützend, aber zumindest haben Sie weniger Sorgen.

Kent Fredric
quelle
0

Vielleicht kann dieser helfen, Sie, so habe ich es für meine Website gemacht, es funktioniert wie ein Zauber:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

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

Wenn Sie dazu PHP verwenden möchten, hat dieser Weg für mich sehr gut funktioniert:


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

Es überprüft die HTTPS-Variable im superglobalen Array $ _SERVER, um festzustellen, ob sie gleich "on" ist. Wenn die Variable nicht gleich on ist.

Squiremaldoon
quelle
-1

Ich habe dieses Skript verwendet und es funktioniert gut über die Website.

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
quelle
-2
<?php 
// Require https
if ($_SERVER['HTTPS'] != "on") {
    $url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    header("Location: $url");
    exit;
}
?>

So einfach.

Buchstabieren
quelle