Come posso forzare gli utenti ad accedere alla mia pagina tramite HTTPS anziché HTTP?


137

Ho solo una pagina a cui voglio forzare l'accesso come pagina HTTPS (PHP su Apache). Come posso fare questo senza fare in modo che l'intera directory richieda HTTPS? Oppure, se si invia un modulo a una pagina HTTPS da una pagina HTTP, lo invia tramite HTTPS anziché HTTP?

Ecco il mio esempio:

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

Voglio accedervi solo attraverso:

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

Certo, posso mettere tutti i collegamenti a questa pagina puntati sulla versione HTTPS, ma ciò non impedisce a qualche sciocco di accedervi tramite HTTP di proposito ...

Una cosa che pensavo fosse mettere un reindirizzamento nell'intestazione del file PHP per verificare che stessero accedendo alla versione HTTPS:

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

Ma quello non può essere il modo giusto, vero?



3
C'è qualche motivo per cui non si richiede solo SSL per tutte le pagine?
Il Tahaan,

Risposte:


177

Il modo in cui l'ho fatto prima è sostanzialmente come quello che hai scritto, ma non ha valori hardcoded:

if ($ _ SERVER ["HTTPS"]! = "on")
{
    header ("Posizione: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    Uscita();
}

15
Hai dimenticato di chiamare exit () per assicurarti che lo script venga chiuso dopo il reindirizzamento. Di solito lo avvolgo in una funzione chiamata requireSSL (). Posso chiamare questo nella parte superiore di qualsiasi pagina che voglio essere crittografato.
Jesse Weigert,

31
Cambia se (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")per correggere gli avvisi PHP.
dave1010,

Le $_SERVER[]variabili non sono modificabili / vulnerabili all'intervento degli utenti?
Arian Faurtosh,

@ArianFaurtosh fonte?
Giovanni

3
@ArianFaurtosh alcuni sono estratti dalle intestazioni dei client, come HTTP_X_FORWARDED, e possono essere manipolati, ma altri come HTTPSo SERVER_PORTsono impostati direttamente dal server web e di solito dovrebbero essere sicuri.
Mahn,

46

Potresti farlo con una direttiva e mod_rewrite su Apache:

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

Se lo desideri, puoi rendere la posizione più intelligente nel tempo utilizzando espressioni regolari .


6
Dove lo metteresti? .htaccess file?

1
REQUEST_URI non include la "stringa di query" (come? Page = 1 & id = 41 ecc.)? Questo è ciò che dice la documentazione di Apache ... Quindi se provo ad accedere a site.com/index.php?page=1&id=12 verrò
Rolf

2
Dalla documentazione di apache: REQUEST_URI Il componente path dell'URI richiesto, come "/index.html". Ciò esclude in particolare la stringa di query disponibile come propria variabile denominata QUERY_STRING. Quindi dovrai aggiungere QUERY_STRING dopo REQUEST_URI
Rolf

2
Devi anche aggiungere la [R] flage dopo quella per farla reindirizzare
Rolf

40

È necessario forzare il client a richiedere HTTPS sempre con le intestazioni 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();
}

Si noti che HSTS è supportato nella maggior parte dei browser moderni, ma non universale. Pertanto, la logica sopra reindirizza manualmente l'utente indipendentemente dal supporto se si verificano su HTTP, quindi imposta l'intestazione HSTS in modo che ulteriori richieste client vengano reindirizzate dal browser, se possibile.


Sono sorpreso che nessuna delle altre risposte includa questa intestazione, è abbastanza importante ... qualche insidia per la combinazione delle due?
keisar,

No ... puoi sicuramente impostare quell'intestazione se vuoi sempre HTTPS. È semplicemente ridondante impostarlo prima e dopo aver effettuato il reindirizzamento. Ho anche modificato la mia risposta sopra per spiegare con maggiore precisione la compatibilità.
Jacob Swartwood,

1
(Redazione del commento originale) Non ho notato il requisito specifico di "solo una pagina". HSTS si applicherà a tutte le pagine; la mia risposta è tecnicamente errata.
Jacob Swartwood,

4
Cordiali saluti, lo standard RFC 6797 sezione 7.2 dice "Un host HSTS NON DEVE includere il campo di intestazione STS nelle risposte HTTP trasmesse su trasporto non sicuro." quindi non è necessario inviarlo quando la richiesta è http regolare, dovrebbe essere ignorata se il browser segue lo standard.
Frank Forte,

1
@mark se c'è un MITM e il tuo sito web non ha questa intestazione, puoi consentire a una sessione compresa di andare su http e le persone inseriscono i loro dettagli e probabilmente non se ne accorgeranno e un reindirizzamento non aiuterà (l'uomo in il mezzo si collegherà al sito tramite https e lo presenterà come http). L'uso di questa intestazione forza HTTPS sul lato client. Ciò è particolarmente importante a causa della recente vulnerabilità della sicurezza WPA2 WiFi.
Rudiger,

19

Ho appena creato un file .htaccess e ho aggiunto:

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

Semplice!


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

8

Dovevo fare qualcosa del genere quando correvo dietro un bilanciamento del carico. Punta del cappello 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;
    }
}

6

Il modo 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);
}

Il modo apache mod_rewrite:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Preferisco il modo PHP perché ci sono casi in cui desidero ignorare i requisiti per SSL. Ad esempio, l'accesso locale alle API e cose come la configurazione automatica di Mozilla Thunderbird, ecc.
Jay,

Il metodo PHP funziona perfettamente per me, altamente raccomandato.
Moxet,

5

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

A volte potresti aver bisogno di assicurarti che l'utente stia navigando sul tuo sito tramite una connessione protetta. Un modo semplice per reindirizzare sempre l'utente alla connessione protetta (https: //) può essere realizzato con un file .htaccess contenente le seguenti righe:

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

Si noti che .htaccess dovrebbe trovarsi nella cartella principale del sito Web.

Nel caso in cui si desideri forzare HTTPS per una cartella specifica, è possibile utilizzare:

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

Il file .htaccess deve essere inserito nella cartella in cui è necessario forzare HTTPS.


5

Ok .. Ora ci sono un sacco di cose su questo ora, ma nessuno completa davvero la domanda "Sicuro". Per me è ridicolo usare qualcosa di insicuro.

A meno che non lo usi come esca.

La propagazione di $ _SERVER può essere modificata per volontà di qualcuno che sa come fare.

Inoltre, come hanno affermato Sazzad Tushar Khan e thebigjc, puoi anche usare httaccess per fare questo e ci sono molte risposte qui che lo contengono.

Aggiungi solo:

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

fino alla fine di ciò che hai nel tuo .httaccess e questo è tutto.

Tuttavia non siamo così sicuri come possiamo essere con questi 2 strumenti.

Il resto è semplice. Se mancano attributi, ad es. ...

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

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


Supponiamo inoltre di aver aggiornato il file httaccess e di controllare:

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

Ci sono molte più variabili che puoi controllare, ad es.

HOST_URI (Se ci sono attributi statici al riguardo da verificare)

HTTP_USER_AGENT (Stessa sessione valori diversi)

Quindi tutto ciò che sto dicendo è non accontentarsi solo dell'uno o dell'altro quando la risposta sta in una combinazione.

Per ulteriori informazioni sulla riscrittura di httaccess consultare i documenti-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Alcuni stack qui -> Forza SSL / https utilizzando .htaccess e mod_rewrite
e
Ottenere l'URL completo del pagina corrente (PHP)
per nominare una coppia.


2
ma ora ricevo il seguente errore: ERR_TOO_MANY_REDIRECTS. Come posso risolvere questo problema?
Pathros,

3

Usa $_SERVER['HTTPS']per dire se è SSL e reindirizza nel posto giusto in caso contrario.

E ricorda, la pagina che visualizza il modulo non ha bisogno di essere alimentata tramite HTTPS, è l'URL post-back che ne ha più bisogno.

Modifica : sì, come indicato di seguito, è meglio avere l'intero processo in HTTPS. È molto più rassicurante - ho sottolineato che il post è la parte più critica. Inoltre, è necessario assicurarsi che tutti i cookie siano impostati in modo sicuro, quindi verranno inviati solo tramite SSL. Anche la soluzione mod_rewrite è molto ingegnosa, l'ho usata per proteggere molte applicazioni sul mio sito web.


È vero che il modulo stesso non deve essere https, sebbene sia una buona idea per la maggior parte delle persone che non lo sanno. Se stanno per inviare il modulo e notare che l'icona del lucchetto non è presente, potrebbero erroneamente presumere che il modulo non sia sicuro.
Graeme Perrow,

1
@Graeme: inoltre nessuno può essere certo che il modulo verrà mai inviato tramite https. L'intero modulo (visualizzato tramite http) potrebbe essere un falso, inviato a un sito in chiaro o http sconosciuto. Https non riguarda solo la crittografia, ma autentica anche il server.
Olaf Kock,

3

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

1

Non mescolare HTTP e HTTPS sulla stessa pagina. Se hai una pagina del modulo che viene servita tramite HTTP, sarò nervoso per l'invio dei dati - non riesco a vedere se l'invio passa su HTTPS o HTTP senza fare una vista sorgente e cercarla.

Servire il modulo su HTTPS insieme al link di invio non è una modifica così pesante per il vantaggio.


1

Se usi Apache o qualcosa di simile a LiteSpeed, che supporta i file .htaccess, puoi fare quanto segue. Se non disponi già di un file .htaccess, dovresti creare un nuovo file .htaccess nella directory principale (in genere dove si trova il tuo index.php). Ora aggiungi queste righe come prime regole di riscrittura nel tuo .htaccess:

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

Hai solo bisogno dell'istruzione "RewriteEngine On" una volta nel tuo .htaccess per tutte le regole di riscrittura, quindi se ce l'hai già, copia semplicemente la seconda e la terza riga.

Spero che aiuti.


Questo è ciò che ha funzionato per me e quello che sto usando nei miei script su un framework simile a Zend 2: non capisco il downvote.
Antonio,

Forse sei stato retrocesso perché la risposta è praticamente la stessa di quella di @MatHatrik pubblicata più di un anno prima?
Appassisci il

1

L'uso di questo NON è abbastanza:

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

Se hai contenuti http (come una fonte di immagini http esterna), il browser rileverà una possibile minaccia. Quindi assicurati che tutti i tuoi ref e src nel tuo codice siano https


1

Ho esaminato molte soluzioni verificando lo stato di $ _SERVER [HTTPS] ma sembra che non sia affidabile perché a volte non viene impostato o impostato su on, off, ecc. Causando il reindirizzamento del ciclo interno dello script.

Ecco la soluzione più affidabile se il tuo server supporta $ _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;
}

Si noti che, a seconda dell'installazione, il server potrebbe non supportare $ _SERVER [SCRIPT_URI] ma, in tal caso, questo è lo script migliore da utilizzare.

Puoi controllare qui: perché alcune installazioni PHP hanno $ _SERVER ['SCRIPT_URI'] e altre no


1

Per coloro che utilizzano IIS l'aggiunta di questa riga in web.config aiuterà:

<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 file di esempio completo

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

La domanda si pone specificamente su Apache, non su IIS.
Quentin,

1
A) non è un tag apache. Apache è indicato tra virgolette. B) è una domanda generica che non ha nulla a che fare con Apache in generale. È applicabile a più server
Web di

0

Non dovresti per motivi di sicurezza. Soprattutto se i cookie sono in gioco qui. Ti lascia aperto agli attacchi di replay basati su cookie.

In entrambi i casi, è necessario utilizzare le regole di controllo di Apache per ottimizzarlo.

Quindi è possibile verificare se HTTPS è abilitato e reindirizzare all'occorrenza, se necessario.

È necessario reindirizzare alla pagina di pagamento solo utilizzando un FORM POST (no get) e gli accessi alla pagina senza un POST devono essere reindirizzati alle altre pagine. (Questo catturerà le persone solo saltando a caldo.)

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

È un buon punto di partenza, mi scuso per non averne di più. Ma davvero dovrebbe spingere tutto attraverso SSL.

È iperprotettivo, ma almeno hai meno preoccupazioni.


0

forse questo può aiutarti, è così che ho fatto per il mio sito Web, funziona come un fascino:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

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

0

Se vuoi usare PHP per farlo, in questo modo ha funzionato davvero bene per me:


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

Controlla la variabile HTTPS nell'array superglobal $ _SERVER per vedere se è uguale a "on". Se la variabile non è uguale a on.


-1

Ho usato questo script e funziona bene attraverso il sito.

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

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

Così facile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.