Bagaimana cara memaksa pengguna untuk mengakses halaman saya melalui HTTPS, bukan HTTP?

137

Saya hanya punya satu halaman yang ingin saya paksa untuk diakses sebagai halaman HTTPS (PHP di Apache). Bagaimana cara melakukan ini tanpa membuat seluruh direktori memerlukan HTTPS? Atau, jika Anda mengirimkan formulir ke halaman HTTPS dari halaman HTTP, apakah dikirimkan melalui HTTPS dan bukan HTTP?

Inilah contoh saya:

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

Saya ingin ini hanya dapat diakses melalui:

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

Tentu, saya dapat meletakkan semua tautan ke halaman ini yang menunjuk ke versi HTTPS, tetapi itu tidak menghentikan orang bodoh untuk mengaksesnya melalui HTTP dengan sengaja ...

Satu hal yang saya pikirkan adalah meletakkan pengalihan di header file PHP untuk memeriksa untuk memastikan bahwa mereka mengakses versi HTTPS:

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

Tapi itu tidak mungkin cara yang benar, bukan?

Wiki
sumber
3
Apakah ada alasan mengapa Anda tidak hanya memerlukan SSL untuk semua halaman?
Tahaan

Jawaban:

178

Cara saya melakukannya sebelumnya pada dasarnya seperti apa yang Anda tulis, tetapi tidak memiliki nilai hardcode:

jika ($ _ SERVER ["HTTPS"]! = "on")
{
    header ("Lokasi: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    keluar();
}
Adam Rosenfield
sumber
15
Anda lupa memanggil exit () untuk memastikan skrip berhenti setelah pengalihan. Saya biasanya membungkusnya dalam fungsi yang disebut requireSSL (). Saya dapat menyebutnya ini di bagian atas halaman mana pun yang ingin saya enkripsi.
Jesse Weigert
31
Ubah jika menjadi (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")untuk memperbaiki pemberitahuan PHP.
dave1010
Bukankah $_SERVER[]variabel dapat diubah / rentan terhadap intervensi pengguna?
Arian Faurtosh
Sumber @ArianFurtosh?
Yohanes
3
@ArianFaurtosh beberapa diekstrak dari header klien, seperti HTTP_X_FORWARDED, dan dapat dimanipulasi, tetapi yang lain suka HTTPSatau SERVER_PORTdisetel langsung dari server web dan biasanya seharusnya aman.
Mahn
46

Anda dapat melakukannya dengan direktif dan mod_rewrite di Apache:

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

Anda dapat membuat Lokasi lebih pintar dari waktu ke waktu menggunakan ekspresi reguler jika Anda mau.

thebigjc
sumber
6
Di mana Anda akan meletakkan ini? file .htaccess?
1
Bukankah REQUEST_URI tidak menyertakan "string kueri" (seperti? Page = 1 & id = 41 dll.)? Itulah yang dikatakan dalam dokumentasi apache ... Jadi jika saya mencoba mengakses site.com/index.php?page=1&id=12 saya akan dialihkan ke site.com/index.php
Rolf
2
Dari apache Dokumentasi: REQUEST_URI Komponen jalur URI yang diminta, seperti "/index.html". Ini terutama mengecualikan string kueri yang tersedia sebagai variabelnya sendiri bernama QUERY_STRING. Jadi, Anda perlu menambahkan QUERY_STRING setelah REQUEST_URI
Rolf
2
Anda juga perlu menambahkan flage [R] setelah itu untuk membuatnya mengalihkan
Rolf
40

Anda harus memaksa klien untuk selalu meminta HTTPS dengan header 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();
}

Harap diperhatikan bahwa HSTS didukung di sebagian besar browser modern, tetapi tidak universal. Dengan demikian, logika di atas secara manual mengalihkan pengguna terlepas dari dukungannya jika mereka berakhir di HTTP, lalu menyetel header HSTS sehingga permintaan klien selanjutnya harus dialihkan oleh browser jika memungkinkan.

Jacob Swartwood
sumber
Saya terkejut bukan dari jawaban lain termasuk tajuk ini, cukup penting ... ada jebakan untuk menggabungkan keduanya?
keisar
Tidak ... Anda pasti dapat menyetel tajuk itu jika Anda menginginkan HTTPS selalu. Ini hanya semacam mubazir untuk mengaturnya sebelum dan sesudah Anda melakukan pengalihan. Saya juga telah mengubah tanggapan saya di atas untuk menjelaskan kompatibilitas dengan lebih akurat.
Jacob Swartwood
1
(Menyunting komentar asli) Saya tidak memperhatikan persyaratan khusus "hanya satu halaman". HSTS akan berlaku untuk semua halaman; jawaban saya secara teknis salah.
Jacob Swartwood
4
FYI, standar RFC 6797 bagian 7.2 mengatakan "Host HSTS TIDAK HARUS menyertakan kolom header STS dalam tanggapan HTTP yang disampaikan melalui pengangkutan tidak aman." jadi tidak perlu mengirimkannya bila requestnya adalah http biasa, sebaiknya diabaikan jika browser mengikuti standar.
Frank Forte
1
@ tandai jika ada MITM dan situs web Anda tidak memiliki tajuk ini, Anda dapat mengizinkan sesi yang terdiri dari pergi ke http dan orang-orang memasukkan detail mereka dan mereka mungkin tidak akan memperhatikan dan pengalihan tidak akan membantu (orang di bagian tengah akan terhubung ke situs melalui https dan menampilkannya sebagai http). Menggunakan tajuk ini akan memaksa HTTPS di sisi klien. Ini sangat penting karena kerentanan keamanan WiFi WPA2 baru-baru ini.
Rudiger
19

Saya baru saja membuat file .htaccess dan menambahkan:

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

Sederhana!

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

Harus melakukan sesuatu seperti ini saat menjalankan penyeimbang beban. Kiat topi 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
sumber
6

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

Cara Apache mod_rewrite:

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Jay
sumber
Saya lebih suka cara PHP karena ada contoh di mana saya ingin mengganti persyaratan untuk SSL. Misalnya, akses lokal ke API dan hal-hal seperti konfigurasi otomatis Mozilla Thunderbird, dll.
Jay
Metode PHP bekerja dengan sempurna untuk saya, sangat disarankan.
Moxet
5

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

Terkadang Anda mungkin perlu memastikan bahwa pengguna menjelajahi situs Anda melalui koneksi yang aman. Cara mudah untuk selalu mengarahkan pengguna ke koneksi aman (https: //) dapat dilakukan dengan file .htaccess yang berisi baris berikut:

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

Harap dicatat bahwa .htaccess harus ditempatkan di folder utama situs web.

Jika Anda ingin memaksa HTTPS untuk folder tertentu, Anda dapat menggunakan:

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

File .htaccess harus ditempatkan di folder tempat Anda perlu memaksa HTTPS.

itsazzad
sumber
5

Oke .. Sekarang ada banyak sekali hal tentang ini sekarang, tetapi tidak ada yang benar-benar menyelesaikan pertanyaan "Aman". Bagi saya, konyol menggunakan sesuatu yang tidak aman.

Kecuali jika Anda menggunakannya sebagai umpan.

Propagasi $ _SERVER dapat diubah sesuai keinginan seseorang yang tahu caranya.

Juga seperti yang Sazzad Tushar Khan dan theebigjc nyatakan Anda juga dapat menggunakan httpaccess untuk melakukan ini dan ada banyak jawaban di sini yang berisi itu.

Tambahkan saja:

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

sampai akhir dari apa yang Anda miliki di .httaccess dan itu.

Tetap saja kami tidak seaman mungkin dengan 2 alat ini.

Selebihnya sederhana. Jika ada atribut yang hilang yaitu ...

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

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


Juga katakan Anda telah memperbarui file httaccess Anda dan Anda memeriksa:

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

Ada lebih banyak variabel yang dapat Anda periksa yaitu ..

HOST_URI (Jika ada atribut statis tentang itu untuk diperiksa)

HTTP_USER_AGENT (Sesi yang sama memiliki nilai yang berbeda)

Jadi yang saya katakan adalah jangan hanya puas dengan satu atau yang lain ketika jawabannya terletak pada kombinasi.

Untuk info penulisan ulang httaccess lebih lanjut, lihat docs-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Beberapa Tumpukan di sini -> Paksa SSL / https menggunakan .htaccess dan mod_rewrite
dan
Mendapatkan URL lengkap dari halaman saat ini (PHP)
untuk menyebutkan beberapa.

JSG
sumber
2
tapi sekarang saya mendapatkan error berikut: ERR_TOO_MANY_REDIRECTS. Bagaimana cara mengatasinya?
Pathros
3

Gunakan $_SERVER['HTTPS']untuk mengetahui apakah itu SSL , dan alihkan ke tempat yang tepat jika tidak.

Dan ingat, halaman yang menampilkan formulir tidak perlu diberi makan melalui HTTPS, URL kiriman baliklah yang paling membutuhkannya.

Sunting : ya, seperti yang ditunjukkan di bawah ini, yang terbaik adalah memiliki seluruh proses dalam HTTPS. Ini jauh lebih meyakinkan - saya menunjukkan bahwa pos adalah bagian paling penting. Selain itu, Anda perlu berhati-hati agar cookie apa pun diatur agar aman, jadi cookie hanya akan dikirim melalui SSL. Solusi mod_rewrite juga sangat bagus, saya telah menggunakannya untuk mengamankan banyak aplikasi di situs web saya sendiri.

DGM
sumber
Memang benar bahwa formulirnya sendiri tidak perlu https, meskipun itu ide yang bagus untuk sebagian besar orang yang tidak mengetahui hal ini. Jika mereka akan mengirimkan formulir dan melihat bahwa ikon gembok tidak ada di sana, mereka mungkin secara keliru menganggap bahwa formulir tersebut tidak aman.
Graeme Perrow
1
@Graeme: Selain itu tidak ada yang dapat yakin bahwa formulir akan dikirim melalui https. Seluruh formulir (ditampilkan melalui http) mungkin palsu, dikirimkan ke situs cleartext yang tidak dikenal atau http. Https bukan hanya tentang enkripsi, tetapi juga mengotentikasi server.
Olaf Kock
3

penggunaan 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
sumber
1

Jangan mencampur HTTP dan HTTPS di halaman yang sama. Jika Anda memiliki halaman formulir yang disajikan melalui HTTP, saya akan gugup untuk mengirimkan data - saya tidak dapat melihat apakah pengiriman melewati HTTPS atau HTTP tanpa melakukan View Source dan memburunya.

Menyajikan formulir melalui HTTPS bersama dengan tautan kirim bukanlah perubahan yang berat untuk keuntungannya.

JBB
sumber
1

Jika Anda menggunakan Apache atau sesuatu seperti LiteSpeed, yang mendukung file .htaccess, Anda dapat melakukan hal berikut. Jika Anda belum memiliki file .htaccess, Anda harus membuat file .htaccess baru di direktori root Anda (biasanya di mana index.php Anda berada). Sekarang tambahkan baris ini sebagai aturan penulisan ulang pertama di .htaccess Anda:

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

Anda hanya membutuhkan instruksi "RewriteEngine On" sekali dalam .htaccess Anda untuk semua aturan penulisan ulang, jadi jika Anda sudah memilikinya, cukup salin baris kedua dan ketiga.

Saya harap ini membantu.

Antonio
sumber
Inilah yang berhasil untuk saya dan apa yang saya gunakan dalam skrip saya sendiri pada Kerangka serupa Zend 2 - Saya tidak mengerti downvote-nya.
Antonio
Mungkin kamu downvoted karena jawabannya hampir sama dengan yang ini dari @MatHatrik yang diposting lebih dari setahun sebelumnya?
Wilt
1

Menggunakan ini TIDAK cukup:

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

Jika Anda memiliki konten http (seperti sumber gambar http eksternal), browser akan mendeteksi kemungkinan ancaman. Jadi pastikan semua ref dan src Anda di dalam kode Anda adalah https

webmaster bourax
sumber
1

Saya telah melalui banyak solusi dengan memeriksa status $ _SERVER [HTTPS] tetapi sepertinya itu tidak dapat diandalkan karena terkadang tidak disetel atau disetel ke hidup, mati, dll. Menyebabkan skrip ke pengalihan loop internal.

Berikut adalah solusi paling andal jika server Anda mendukung $ _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;
}

Harap dicatat bahwa tergantung pada instalasi Anda, server Anda mungkin tidak mendukung $ _SERVER [SCRIPT_URI] tetapi jika ya, ini adalah skrip yang lebih baik untuk digunakan.

Anda dapat memeriksa di sini: Mengapa beberapa instalasi PHP memiliki $ _SERVER ['SCRIPT_URI'] dan yang lainnya tidak

Tarik
sumber
1

Bagi mereka yang menggunakan IIS menambahkan baris ini di web.config akan membantu:

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

File contoh lengkap

<?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
sumber
Pertanyaannya secara khusus menanyakan tentang Apache, bukan IIS.
Quentin
1
A) apache yang tidak diberi tag. Apache diukur di antara tanda kutip. B) ini adalah pertanyaan umum yang tidak ada hubungannya dengan apache secara umum. Ini berlaku untuk beberapa server web pendukung php
Tschallacka
1

Jika Anda ingin menggunakan PHP untuk melakukan ini, maka cara ini bekerja dengan sangat baik untuk saya:


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

Ia memeriksa variabel HTTPS dalam array superglobal $ _SERVER untuk melihat apakah itu sama dengan "on". Jika variabel tidak sama dengan on.

squiremaldoon
sumber
0

Anda tidak boleh karena alasan keamanan. Apalagi jika cookie sedang dimainkan di sini. Ini membuat Anda terbuka lebar untuk serangan replay berbasis cookie.

Apa pun itu, Anda harus menggunakan aturan kontrol Apache untuk menyesuaikannya.

Kemudian Anda dapat menguji HTTPS yang diaktifkan dan mengalihkan sesuai kebutuhan jika diperlukan.

Anda harus mengarahkan ke halaman pembayaran hanya dengan menggunakan FORM POST (no get), dan akses ke halaman tanpa POST harus diarahkan kembali ke halaman lain. (Ini akan membuat orang-orang melompat-lompat.)

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

Merupakan tempat yang baik untuk memulai, maaf karena tidak memberikan lebih banyak. Tetapi Anda benar - benar harus mendorong semuanya melalui SSL.

Itu terlalu protektif, tapi setidaknya Anda tidak terlalu khawatir.

Kent Fredric
sumber
0

mungkin yang ini bisa membantu, Anda, begitulah yang saya lakukan untuk situs web saya, berfungsi seperti pesona:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

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

Saya telah menggunakan skrip ini dan bekerja dengan baik di seluruh situs.

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

Itu mudah.

Mengeja
sumber