Buộc SSL / https sử dụng .htaccess và mod_rewrite


Câu trả lời:


438

Đối với Apache, bạn có thể sử dụng mod_sslđể buộc SSL bằng SSLRequireSSL Directive:

Lệnh này cấm truy cập trừ khi HTTP qua SSL (tức là HTTPS) được bật cho kết nối hiện tại. Điều này rất tiện dụng bên trong máy chủ hoặc thư mục ảo hỗ trợ SSL để bảo vệ chống lại các lỗi cấu hình làm lộ ra những thứ cần được bảo vệ. Khi có lệnh này, tất cả các yêu cầu đều bị từ chối không sử dụng SSL.

Điều này sẽ không làm chuyển hướng đến https mặc dù. Để chuyển hướng, hãy thử cách sau với mod_rewritetrong tệp .htaccess của bạn

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

hoặc bất kỳ phương pháp khác nhau được đưa ra tại

Bạn cũng có thể giải quyết vấn đề này từ bên trong PHP trong trường hợp nhà cung cấp của bạn đã vô hiệu hóa .htaccess (điều này khó xảy ra vì bạn đã yêu cầu, nhưng dù sao đi nữa)

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

1
Điều này thật tuyệt vời trong tình huống của chúng tôi vì chúng tôi hiện có hỗn hợp lưu lượng truy cập http và https. Đối với khu vực quản trị viên của chúng tôi, chúng tôi vừa xuất hiện tập lệnh .htaccess trong khi giữ phần còn lại của trang web http.
Michael J. Calkins

1
Khi tôi sử dụng phương thức mod_rewrite, tôi được gửi tới https nhưng với lỗi "Trang không chuyển hướng đúng".
Công nghệ

11
Theo dõi: Nếu bạn gặp sự cố tương tự, hãy kiểm tra máy chủ và các biến HTTP. Nếu máy chủ của bạn sử dụng proxy, bạn có thể muốn sử dụng %{HTTP:X-Forwarded-Proto}hoặc %{HTTP:X-Real-Port}các biến để kiểm tra xem SSL có được bật hay không.
Công nghệ

8
Nếu bạn gặp phải các vòng lặp chuyển hướng trên các máy chủ chạy phía sau proxy ( CloudFlare , Openshift ), hãy xem câu trả lời này để biết giải pháp phù hợp với trường hợp đó.
raphinesse

4
@GTodorov - Loại bỏ không gian đã phá vỡ cách viết lại cho tôi. Từ kiến ​​thức (giới hạn) của tôi về viết lại, cú pháp là RewriteRule <input-pattern> <output-url>. Do đó, không gian cần phải ở đó và người duy nhất ^chỉ nói "khớp tất cả các URL đầu vào".
Nhân sư

54

Tôi tìm thấy một mod_rewritegiải pháp hoạt động tốt cho cả máy chủ proxy và máy chủ không được cung cấp.

Nếu bạn đang sử dụng CloudFlare, AWS Elastic Load Balance, Heroku, OpenShift hoặc bất kỳ giải pháp Cloud / PaaS nào khác và bạn đang gặp phải các vòng chuyển hướng với các chuyển hướng HTTPS bình thường, thay vào đó hãy thử đoạn trích sau.

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]

Thật là tuyệt vời! Nhưng có lẽ nó là cần thiết để thêm điều kiện bài? RewriteCond% {REQUEST_METHOD}! ^ POST $
Aleksej

@Aleksej Đúng, điều này phá vỡ các yêu cầu POST không được mã hóa. Nhưng tôi nghĩ rằng đây là một điều tốt. Bằng cách này, mọi người sẽ nhận thấy họ đang làm gì đó sai. Tôi đoán điều tốt nhất sẽ là chuyển hướng họ đến một trang thông báo cho họ về cách sử dụng dịch vụ của bạn đúng cách.
raphinesse

@raphinesse Bạn có biết câu trả lời của câu hỏi này không: stackoverflow.com/questions/51951082/iêu
RRN

36

Giải pháp PHP

Mượn trực tiếp từ câu trả lời rất toàn diện của Gordon, tôi lưu ý rằng câu hỏi của bạn đề cập đến việc cụ thể theo trang trong việc buộc các kết nối 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>' );
    }
  }
}

Sau đó, gần với đầu của các trang mà bạn muốn buộc kết nối qua PHP, bạn có thể require()một tệp tập trung có chứa các chức năng tùy chỉnh này (và bất kỳ trang nào khác), sau đó chỉ cần chạy forceHTTPS()chức năng.

Giải pháp HTACCESS / mod_rewrite

Tôi đã không thực hiện loại giải pháp này một cách cá nhân (tôi có xu hướng sử dụng giải pháp PHP, như cách đơn giản ở trên, vì nó đơn giản), nhưng ít nhất sau đây có thể là một khởi đầu tốt.

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]

Vì tò mò, tại sao RewriteCond %{REQUEST_METHOD} !^POST$?
depoulo

12
Bởi vì các tham số POST không được giữ lại trên một chuyển hướng. Bạn có thể bỏ qua dòng đó nếu bạn muốn đảm bảo rằng tất cả các lần gửi POST đều an toàn (mọi bài nộp POST không bảo đảm sẽ bị bỏ qua).
Luke Stevenson

@Lucanos - Làm cách nào để viết RewriteCond mà không buộc chuyển hướng đến http hoặc https khi POST? .Htaccess của tôi buộc HTTPS trên một số trang cụ thể và sau đó buộc HTTP trên phần còn lại. Tuy nhiên, trên các trang HTTPS, có các biểu mẫu gửi đến web gốc của tôi. Biểu mẫu chỉ định url hành động là HTTPS. Tuy nhiên, vì gốc web không phải là một trong những trang được chỉ định để buộc HTTPS, nên .htaccess của tôi sau đó buộc chuyển hướng - có nghĩa là các biến POST bị mất. Làm cách nào để ngăn chặn chuyển hướng trên POST?
StackOverflowNewbie

1
@StackOverflowNewbie: Dòng RewriteCond %{REQUEST_METHOD} !^POST$này sẽ ngăn việc gửi POST bị ảnh hưởng bởi các chuyển hướng này.
Luke Stevenson

Tôi thích phiên bản PHP này. Sẽ tốt hơn nhiều vì nó xem xét POST và xử lý tốt hơn nếu các tiêu đề đã được gửi.
TheStoryCoder

10

Mod-viết lại giải pháp dựa trên:

Sử dụng mã sau trong htaccess sẽ tự động chuyển tiếp tất cả các yêu cầu http sang https.

RewriteEngine on

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

Điều này sẽ chuyển hướng các yêu cầu không phải wwwwww http của bạn sang phiên bản www của https.

Một giải pháp khác (Apache 2.4 *)

RewriteEngine on

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

Điều này không hoạt động trên các phiên bản thấp hơn của apache vì biến% {REQUEST_SCHEME} đã được thêm vào mod-viết lại từ 2.4.


9

Tôi chỉ muốn chỉ ra rằng Apache có các quy tắc kế thừa tồi tệ nhất khi sử dụng nhiều tệp .htaccess trên độ sâu thư mục. Hai cạm bẫy chính:

  • Chỉ các quy tắc có trong tệp .htaccess sâu nhất sẽ được thực hiện theo mặc định. Bạn phải chỉ định lệnh RewriteOptions InheritDownBefore(hoặc tương tự) để thay đổi điều này. (xem câu hỏi)
  • Mẫu được áp dụng cho đường dẫn tệp liên quan đến thư mục con và không phải thư mục trên có chứa tệp .htaccess với quy tắc đã cho. (xem thảo luận)

Điều này có nghĩa là giải pháp toàn cầu gợi ý trên Apache Wiki không không có tác dụng nếu bạn sử dụng bất kỳ tập tin .htaccess khác trong thư mục con. Tôi đã viết một phiên bản sửa đổi mà:

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/

0

Đơn giản và dễ dàng, chỉ cần thêm sau

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

Đây là khá nhiều những gì mọi người trên Internet bảo bạn làm để buộc https. Tuy nhiên, mỗi khi tôi làm điều đó, toàn bộ trang web của tôi trở thành FORBIDDEN hoặc Bạn không được phép xem. đại loại như thế ... tôi đang làm gì sai? Tôi chỉ muốn biết nếu bạn có bất kỳ ý tưởng trước khi tôi gửi một câu hỏi về điều này.
ThN 14/12/18

Tôi gặp vấn đề tương tự và tôi phải áp dụng các quy tắc cho tệp https.conf. Xem câu trả lời của tôi dưới đây.
Risteard

-1

Mã này làm việc cho tôi

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

-1

Đơn giản

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

thay thế url của bạn bằng example.com


KHÔNG! URL trang web cần phải năng động.
Amir Savand

-1

chỉ cần buộc SSL với Apache .htaccess bạn có thể sử dụng

SSLOptions +StrictRequire
SSLRequireSSL

để chuyển hướng câu trả lời trên là chính xác


-1

Hãy thử mã này, nó sẽ hoạt động cho tất cả các phiên bản URL như

  • trang 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]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.