Paksa SSL / https menggunakan .htaccess dan mod_rewrite

234

Bagaimana saya bisa memaksa ke SSL / https menggunakan halaman .htaccess dan mod_rewrite khusus dalam PHP.

Sanjay Shah
sumber

Jawaban:

438

Untuk Apache, Anda dapat menggunakan mod_ssluntuk memaksa SSL dengan SSLRequireSSL Directive:

Arahan ini melarang akses kecuali HTTP melalui SSL (yaitu HTTPS) diaktifkan untuk koneksi saat ini. Ini sangat berguna di dalam virtual host atau direktori virtual yang diaktifkan untuk membela terhadap kesalahan konfigurasi yang mengekspos hal-hal yang harus dilindungi. Ketika arahan ini hadir, semua permintaan ditolak yang tidak menggunakan SSL.

Ini tidak akan melakukan redirect ke https. Untuk mengarahkan, coba yang berikut ini dengan mod_rewritefile .htaccess Anda

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

atau salah satu dari berbagai pendekatan yang diberikan di

Anda juga dapat menyelesaikan ini dari dalam PHP jika penyedia Anda telah menonaktifkan .htaccess (yang tidak mungkin karena Anda memintanya, tapi toh)

if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
    if(!headers_sent()) {
        header("Status: 301 Moved Permanently");
        header(sprintf(
            'Location: https://%s%s',
            $_SERVER['HTTP_HOST'],
            $_SERVER['REQUEST_URI']
        ));
        exit();
    }
}
Gordon
sumber
1
Ini bagus dalam situasi kami karena saat ini kami memiliki campuran traffic http dan https. Untuk area admin kami, kami baru saja membuka skrip .htaccess sambil menjaga sisa situs http.
Michael J. Calkins
1
Ketika saya menggunakan metode mod_rewrite, saya dikirim ke https tetapi dengan kesalahan "Halaman tidak mengarahkan ulang dengan benar".
Czechnology
11
Tindak lanjut: Jika Anda mengalami masalah serupa, periksa variabel server dan HTTP Anda. Jika server Anda menggunakan proxy, Anda mungkin ingin menggunakan %{HTTP:X-Forwarded-Proto}atau %{HTTP:X-Real-Port}variabel untuk memeriksa apakah SSL dihidupkan.
Czechnology
8
Jika Anda mengalami pengalihan loop pada server yang berjalan di belakang proxy ( CloudFlare , Openshift ), lihat jawaban ini untuk solusi yang bekerja untuk kasus itu juga.
raphinesse
4
@ GTodorov - Menghapus ruang memecahkan rewriterule untuk saya. Dari pengetahuan (terbatas) saya tentang penulisan ulang, sintaksnya adalah RewriteRule <input-pattern> <output-url>. Jadi, ruang harus ada di sana, dan single itu ^hanya mengatakan "cocokkan semua URL input".
Sphinxxx
54

Saya menemukan mod_rewritesolusi yang berfungsi baik untuk server proksi dan tidak proksi.

Jika Anda menggunakan CloudFlare, AWS Elastic Load Balancing, Heroku, OpenShift atau solusi Cloud / PaaS lainnya dan Anda mengalami loop pengalihan dengan pengalihan HTTPS yang normal, coba snippet berikut sebagai gantinya.

RewriteEngine On

# If we receive a forwarded http request from a proxy...
RewriteCond %{HTTP:X-Forwarded-Proto} =http [OR]

# ...or just a plain old http request directly from the client
RewriteCond %{HTTP:X-Forwarded-Proto} =""
RewriteCond %{HTTPS} !=on

# Redirect to https version
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
raphinesse
sumber
Ini brilian, terima kasih! Tetapi mungkin perlu menambahkan kondisi posting? RewriteCond% {REQUEST_METHOD}! ^ POST $
Aleksej
@Alexej Benar, ini memecah permintaan POST tidak terenkripsi. Tetapi saya pikir ini adalah hal yang baik. Dengan cara ini, orang akan memperhatikan bahwa mereka melakukan sesuatu yang salah. Saya kira hal terbaik adalah mengarahkan mereka ke halaman yang memberi tahu mereka tentang cara menggunakan layanan Anda dengan benar.
raphinesse
@raphinesse Apakah Anda tahu jawaban pertanyaan ini: stackoverflow.com/questions/51951082/…
RRN
36

Solusi PHP

Meminjam langsung dari jawaban Gordon yang sangat komprehensif, saya perhatikan bahwa pertanyaan Anda menyebutkan spesifik-halaman dalam memaksakan koneksi HTTPS / SSL.

function forceHTTPS(){
  $httpsURL = 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
  if( count( $_POST )>0 )
    die( 'Page should be accessed with HTTPS, but a POST Submission has been sent here. Adjust the form to point to '.$httpsURL );
  if( !isset( $_SERVER['HTTPS'] ) || $_SERVER['HTTPS']!=='on' ){
    if( !headers_sent() ){
      header( "Status: 301 Moved Permanently" );
      header( "Location: $httpsURL" );
      exit();
    }else{
      die( '<script type="javascript">document.location.href="'.$httpsURL.'";</script>' );
    }
  }
}

Kemudian, sebagai dekat dengan bagian atas halaman-halaman ini yang ingin Anda paksa sambungkan melalui PHP, Anda dapat require()file terpusat yang berisi fungsi kustom ini (dan yang lainnya), dan kemudian jalankan saja forceHTTPS()fungsinya.

Solusi HTACCESS / mod_rewrite

Saya belum mengimplementasikan solusi semacam ini secara pribadi (saya cenderung menggunakan solusi PHP, seperti yang di atas, untuk kesederhanaannya), tetapi berikut ini mungkin, setidaknya, awal yang baik.

RewriteEngine on

# Check for POST Submission
RewriteCond %{REQUEST_METHOD} !^POST$

# Forcing HTTPS
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{SERVER_PORT} 80
# Pages to Apply
RewriteCond %{REQUEST_URI} ^something_secure [OR]
RewriteCond %{REQUEST_URI} ^something_else_secure
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

# Forcing HTTP
RewriteCond %{HTTPS} =on [OR]
RewriteCond %{SERVER_PORT} 443
# Pages to Apply
RewriteCond %{REQUEST_URI} ^something_public [OR]
RewriteCond %{REQUEST_URI} ^something_else_public
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
Luke Stevenson
sumber
karena penasaran, mengapa RewriteCond %{REQUEST_METHOD} !^POST$?
depoulo
12
Karena parameter POST tidak dipertahankan pada pengalihan. Anda dapat menghilangkan baris itu jika Anda ingin memastikan bahwa semua pengiriman POST aman (setiap pengiriman POST yang tidak aman akan diabaikan).
Luke Stevenson
@Lucanos - Bagaimana cara menulis RewriteCond yang tidak memaksa redirect ke http atau https ketika POST? .Htaccess saya memaksa HTTPS pada halaman tertentu, dan kemudian memaksa HTTP untuk yang lain. Namun, pada halaman HTTPS, ada formulir yang dikirimkan ke root web saya. Formulir menentukan url tindakan sebagai HTTPS. Namun, karena root web bukan salah satu halaman yang ditentukan untuk memaksa HTTPS, .htaccess saya kemudian memaksa pengalihan - yang berarti variabel POST hilang. Bagaimana saya mencegah pengalihan pada POST?
StackOverflowNewbie
1
@StackOverflowNewbie: Baris RewriteCond %{REQUEST_METHOD} !^POST$harus mencegah pengiriman POST agar tidak terpengaruh oleh pengalihan ini.
Luke Stevenson
Saya suka versi PHP ini. Jauh lebih baik karena menganggap POST dan menangani lebih baik jika tajuk sudah dikirim.
TheStoryCoder
10

Solusi berbasis mod-rewrite:

Menggunakan kode berikut di htaccess secara otomatis meneruskan semua permintaan http ke https.

RewriteEngine on

RewriteCond %{HTTPS}::%{HTTP_HOST} ^off::(?:www\.)?(.+)$
RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,L,R]

Ini akan mengarahkan permintaan non-www dan www http Anda ke www https versi .

Solusi lain (Apache 2.4 *)

RewriteEngine on

RewriteCond %{REQUEST_SCHEME}::%{HTTP_HOST} ^http::(?:www\.)?(.+)$
RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,L,R]

Ini tidak berfungsi pada versi apache yang lebih rendah karena variabel% {REQUEST_SCHEME} ditambahkan ke mod-rewrite sejak 2.4.

starkeen
sumber
9

Saya hanya ingin menunjukkan bahwa Apache memiliki aturan pewarisan terburuk ketika menggunakan beberapa file .htaccess di kedalaman direktori. Dua perangkap utama:

  • Hanya aturan yang terkandung dalam file .htaccess terdalam yang akan dilakukan secara default. Anda harus menentukan RewriteOptions InheritDownBeforearahan (atau yang serupa) untuk mengubahnya. (lihat pertanyaan)
  • Pola ini diterapkan ke path file relatif ke subdirektori dan bukan direktori atas yang berisi file .htaccess dengan aturan yang diberikan. (lihat diskusi)

Ini berarti solusi global menyarankan pada Apache Wiki tidak tidak bekerja jika Anda menggunakan file .htaccess lainnya di subdirektori. Saya menulis versi modifikasi yang:

RewriteEngine On
# This will enable the Rewrite capabilities

RewriteOptions InheritDownBefore
# This prevents the rule from being overrided by .htaccess files in subdirectories.

RewriteCond %{HTTPS} !=on
# This checks to make sure the connection is not already HTTPS

RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [QSA,R,L]
# This rule will redirect users from their original location, to the same location but using HTTPS.
# i.e.  http://www.example.com/foo/ to https://www.example.com/foo/
lpd
sumber
0

Sederhana dan Mudah, cukup tambahkan berikut ini

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Saurabh Mistry
sumber
Ini adalah apa yang dikatakan orang-orang di seluruh internet agar Anda lakukan untuk memaksa https. Namun, setiap kali saya melakukannya, seluruh situs web saya menjadi DILARANG atau Anda tidak memiliki izin untuk melihatnya. sesuatu seperti itu ... Apa yang saya lakukan salah? Saya hanya ingin tahu apakah Anda punya ide sebelum saya mengirim pertanyaan tentang ini.
ThN
Saya memiliki masalah yang sama dan saya harus menerapkan aturan ke file https.conf. Lihat jawaban saya di bawah ini.
Risteard
-1

Kode ini berfungsi untuk saya

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP:X-HTTPS} !1
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
Alexufo
sumber
-1

Sederhana

RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.example\.com)(:80)? [NC]
RewriteRule ^(.*) https://example.com/$1 [R=301,L]
order deny,allow

ganti url Anda dengan example.com

Sepehr Norouzi
sumber
TIDAK! URL situs harus dinamis.
Amir Savand
-1

hanya untuk memaksa SSL dengan Apache .htaccess yang dapat Anda gunakan

SSLOptions +StrictRequire
SSLRequireSSL

untuk mengarahkan jawaban di atas sudah benar

webdesignwien
sumber
-1

coba kode ini, ini akan berfungsi untuk semua versi URL seperti

  • situs web.com
  • www.website.com
  • http://website.com
  • http://www.website.com

    RewriteCond %{HTTPS} off
    RewriteCond %{HTTPS_HOST} !^www.website.com$ [NC]
    RewriteRule ^(.*)$ https://www.website.com/$1 [L,R=301]
Kashif Latif
sumber