Wymuś SSL / https przy użyciu .htaccess i mod_rewrite

234

Jak mogę wymusić SSL / https używając .htaccess i strony mod_rewrite specyficznej dla PHP.

Sanjay Shah
źródło

Odpowiedzi:

438

W przypadku Apache można użyć mod_ssldo wymuszenia protokołu SSL za pomocą SSLRequireSSL Directive:

Niniejsza dyrektywa zabrania dostępu, chyba że dla bieżącego połączenia włączony jest HTTP przez SSL (tj. HTTPS). Jest to bardzo przydatne w wirtualnym hoście lub katalogach z obsługą SSL do obrony przed błędami konfiguracji, które ujawniają elementy, które powinny być chronione. Gdy ta dyrektywa jest obecna, wszystkie żądania są odrzucane, które nie używają protokołu SSL.

Nie spowoduje to jednak przekierowania do https. Aby przekierować, spróbuj wykonać następujące czynności mod_rewritew pliku .htaccess

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

lub dowolne z różnych podejść podanych w

Możesz również rozwiązać ten problem z poziomu PHP, jeśli Twój dostawca wyłączył .htaccess (co jest mało prawdopodobne, ponieważ poprosiłeś o to, ale i tak)

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
źródło
1
Jest to świetne w naszej sytuacji, ponieważ obecnie mamy połączenie ruchu http i https. W naszym obszarze administracyjnym właśnie wpisaliśmy skrypt .htaccess, zachowując resztę strony http.
Michael J. Calkins
1
Kiedy korzystam z metody mod_rewrite, wysyłam do https, ale pojawia się błąd „Strona nie przekierowuje poprawnie”.
Czechnology
11
Kontynuacja: jeśli masz podobne problemy, sprawdź zmienne serwera i HTTP. Jeśli Twój serwer używa serwerów proxy, możesz użyć %{HTTP:X-Forwarded-Proto}lub %{HTTP:X-Real-Port}zmiennych, aby sprawdzić, czy protokół SSL jest włączony.
Czechnology
8
Jeśli występują pętle przekierowania na serwerach działających za serwerami proxy ( CloudFlare , Openshift ), zapoznaj się z tą odpowiedzią, aby znaleźć rozwiązanie, które działa również w tym przypadku.
raphinesse
4
@GTodorov - Usunięcie miejsca złamało dla mnie przepisywanie. Z mojej (ograniczonej) wiedzy o przepisywaniu tekstu wynika, że ​​składnia jest następująca RewriteRule <input-pattern> <output-url>. Tak więc przestrzeń musi tam być, a singiel ^mówi „dopasuj wszystkie wejściowe adresy URL”.
Sphinxxx
54

Znalazłem mod_rewriterozwiązanie, które działa dobrze zarówno na serwerach proxy, jak i bez proxy.

Jeśli korzystasz z CloudFlare, AWS Elastic Load Balancing, Heroku, OpenShift lub innego rozwiązania Cloud / PaaS i występują pętle przekierowań z normalnymi przekierowaniami HTTPS, wypróbuj następujący fragment kodu.

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
źródło
To jest genialne dzięki! Ale może trzeba dodać warunek postu? RewriteCond% {REQUEST_METHOD}! ^ POST $
Aleksej
@Aleksej To prawda, że ​​łamie nieszyfrowane żądania POST. Ale myślę, że to dobra rzecz. W ten sposób ludzie zauważą, że robią coś złego. Myślę, że najlepszą rzeczą byłoby przekierowanie ich na stronę, która informuje ich o tym, jak prawidłowo korzystać z usługi.
raphinesse
@raphinesse Czy znasz odpowiedź na to pytanie: stackoverflow.com/questions/51951082/…
RRN
36

Rozwiązanie PHP

Pożyczając bezpośrednio z bardzo wyczerpującej odpowiedzi Gordona, zauważam, że twoje pytanie wspomina o specyfice strony w wymuszaniu połączeń 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>' );
    }
  }
}

Następnie, jak najbliżej góry tych stron, które chcesz zmusić do połączenia przez PHP, możesz require()scentralizowany plik zawierający tę (i dowolną inną) funkcję niestandardową, a następnie po prostu uruchomić tę forceHTTPS()funkcję.

Rozwiązanie HTACCESS / mod_rewrite

Nie wdrożyłem tego rodzaju rozwiązania osobiście (zwykle używałem rozwiązania PHP, takiego jak powyższe, ze względu na jego prostotę), ale poniższe działania mogą być przynajmniej dobrym początkiem.

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
źródło
z ciekawości, dlaczego RewriteCond %{REQUEST_METHOD} !^POST$?
depoulo
12
Ponieważ parametry POST nie są zachowywane na przekierowaniu. Możesz pominąć ten wiersz, jeśli chcesz się upewnić, że wszystkie zgłoszenia POST są bezpieczne (wszelkie niezabezpieczone zgłoszenia POST zostaną zignorowane).
Luke Stevenson
@Lucanos - Jak napisać RewriteCond, który nie wymusza przekierowania na http lub https podczas testu POST? Mój .htaccess wymusza HTTPS na określonych stronach, a następnie wymusza HTTP na pozostałych. Jednak na stronach HTTPS są formularze przesyłane do mojego katalogu głównego. Formularz określa adres URL akcji jako HTTPS. Ponieważ jednak katalog główny nie jest jedną z tych stron, które zostały określone w celu wymuszenia HTTPS, mój .htaccess wymusza następnie przekierowanie - co oznacza, że ​​zmienne POST są tracone. Jak zapobiec przekierowaniom przy POST?
StackOverflowNewbie
1
@StackOverflowNewbie: Linia RewriteCond %{REQUEST_METHOD} !^POST$powinna zapobiegać wpływowi tych przekierowań na zgłoszenia POST.
Luke Stevenson
Podoba mi się ta wersja PHP. Jest o wiele lepszy, ponieważ uwzględnia POST i radzi sobie lepiej, jeśli nagłówki zostały już wysłane.
TheStoryCoder
10

Rozwiązanie oparte na modyfikacji przepisu:

Użycie następującego kodu w htaccess automatycznie przesyła wszystkie żądania http do https.

RewriteEngine on

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

Spowoduje to przekierowanie twoich żądań innych niż www i www http do wersji www https.

Inne rozwiązanie (Apache 2.4 *)

RewriteEngine on

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

Nie działa to na niższych wersjach apache, ponieważ zmienna% {REQUEST_SCHEME} została dodana do mod-rewrite od wersji 2.4.

starkeen
źródło
9

Chciałbym tylko zauważyć, że Apache ma najgorsze reguły dziedziczenia, gdy używa się wielu plików .htaccess w różnych głębokościach katalogów. Dwie kluczowe pułapki:

  • Domyślnie będą wykonywane tylko reguły zawarte w najgłębszym pliku .htaccess. Musisz określić RewriteOptions InheritDownBeforedyrektywę (lub podobną), aby to zmienić. (patrz pytanie)
  • Wzorzec jest stosowany do ścieżki pliku względem podkatalogu, a nie do górnego katalogu zawierającego plik .htaccess z podaną regułą. (patrz dyskusja)

Oznacza to, że zasugerował globalne rozwiązanie na Apache Wiki ma nie działać, jeśli używasz innych plików .htaccess w podkatalogów. Napisałem zmodyfikowaną wersję, która:

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
źródło
0

Proste i łatwe, wystarczy dodać następujące

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Saurabh Mistry
źródło
To jest prawie to, co ludzie w Internecie każą ci wymusić https. Jednak za każdym razem, gdy to robię, cała moja witryna staje się ZABRONIONA lub nie masz uprawnień do przeglądania. coś takiego ... Co robię źle? Chcę tylko wiedzieć, czy masz jakiś pomysł, zanim odpowiem na to pytanie.
ThN
Miałem podobny problem i musiałem zastosować reguły do ​​pliku https.conf. Zobacz moją odpowiedź poniżej.
Risteard
-1

Ten kod działa dla mnie

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

Prosty:

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

zamień swój adres URL na example.com

Sepehr Norouzi
źródło
NIE! Adres URL witryny musi być dynamiczny.
Amir Savand
-1

do wymuszania SSL przy pomocy Apache .htaccess, którego możesz użyć

SSLOptions +StrictRequire
SSLRequireSSL

w przypadku przekierowania powyższa odpowiedź jest poprawna

webdesignwien
źródło
-1

wypróbuj ten kod, będzie działać dla wszystkich wersji adresów URL, takich jak

  • website.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
źródło