242

Làm cách nào để buộc SSL / https bằng cách sử dụng trang .htaccess và mod_rewrite cụ thể trong PHP.

|
449

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

Chỉ thị 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 hữu ích bên trong máy chủ hoặc thư mục ảo hỗ trợ SSL để bảo vệ khỏi các lỗi cấu hình làm lộ nội dung cần được bảo vệ. Khi có chỉ thị này, tất cả các yêu cầu đều bị từ chối không sử dụng SSL.

Tuy nhiên, điều này sẽ không chuyển hướng đến https. Để 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 tiếp cận nào đượ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 đã tắt .htaccess (điều này khó xảy ra vì bạn đã yêu cầu nó, nhưng dù sao)

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
    Đây là điều 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ị của chúng tôi, chúng tôi chỉ nhập tập lệnh .htaccess trong khi giữ phần còn lại của trang web http. –  23:11:52 24/09/2014
  • 1
    Khi tôi sử dụng phương thức mod_rewrite, tôi được chuyển đến https nhưng gặp lỗi "Trang không chuyển hướng đúng cách". –  12:00:38 09/10/2014
  • 1
    Theo dõi: Nếu bạn đang gặp sự cố tương tự, hãy kiểm tra máy chủ và các biến HTTP của bạn. 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. –  12:47:09 09/10/2014
  • 1
    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 sau proxy ( CloudFlare , Openshift ), hãy xem câu trả lời này để biết giải pháp cũng hoạt động cho trường hợp đó. –  11:58:29 03/12/2015
  • 1
    @GTodorov - Việc xóa khoảng trắng đã phá vỡ quy tắc viết lại đối với tôi. Từ kiến ​​thức (hạn chế) của tôi về máy viết lại, cú pháp là RewriteRule <input-pattern> <output-url>. Vì vậy, không gian cần phải có ở đó và duy nhất ^chỉ nói "khớp với tất cả các URL đầu vào". –  13:37:36 30/06/2016
56

Tôi đã tìm thấy một mod_rewritegiải pháp hoạt động tốt cho cả máy chủ được ủy quyền và không được hỗ trợ.

Nếu bạn đang sử dụng CloudFlare, AWS Elastic Load Balancing, 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 lặp chuyển hướng với chuyển hướng HTTPS thông thường, hãy thử đoạn mã 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]
|
  • 1
    Điều này thật tuyệt vời! Nhưng có lẽ nó được yêu cầu thêm điều kiện đăng bài? RewriteCond% {REQUEST_METHOD}! ^ POST $ –  09:40:34 16/09/2017
  • 1
    @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ĩ đâ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 sai điều gì đó. Tôi đoán điều tốt nhất là chuyển hướng họ đến một trang thông báo cho họ về cách sử dụng đúng dịch vụ của bạn. –  11:53:24 20/03/2018
  • 1
    @raphinesse Đỗ bạn biết câu trả lời của câu hỏi này: stackoverflow.com/questions/51951082/... –  14:37:49 21/08/2018
37

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 trang cụ thể trong việc buộ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 đầu các trang này mà bạn muốn buộc kết nối qua PHP, bạn có thể tạo require()một tệp tập trung chứa các hàm tùy chỉnh này (và bất kỳ hàm tùy chỉnh nào khác) và sau đó chỉ cần chạy forceHTTPS()hàm.

Giải pháp HTACCESS / mod_rewrite

Cá nhân tôi chưa thực hiện loại giải pháp này (tôi có xu hướng sử dụng giải pháp PHP, giống như giải pháp ở trên, vì nó đơn giản), nhưng ít nhất những điều 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]
|
  • 1
    vì tò mò, tại sao RewriteCond %{REQUEST_METHOD} !^POST$? –  06:43:30 29/06/2013
  • 1
    Bởi vì các thông số POST không được giữ lại trên 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 lần gửi POST không an toàn sẽ bị bỏ qua). –  06:35:04 30/06/2013
  • 1
    @Lucanos - Làm cách nào để viết RewriteCond 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 các trang cụ thể nhất định và sau đó buộc HTTP trên các trang còn lại. Tuy nhiên, trên các trang HTTPS, có những biểu mẫu được gửi đến trang web gốc của tôi. Biểu mẫu chỉ định url hành động là HTTPS. Tuy nhiên, vì web gốc không phải là một trong những trang được chỉ định để buộc HTTPS, .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 chuyển hướng trên POST? –  19:23:20 08/07/2014
  • 1
    @StackOverflowNewbie: Dòng RewriteCond %{REQUEST_METHOD} !^POST$này phải ngăn chặn việc gửi POST bị ảnh hưởng bởi những chuyển hướng này. –  06:15:30 09/07/2014
  • 1
    Tôi thích phiên bản PHP này. Nó tốt hơn nhiều vì nó coi là một ĐĂNG và xử lý tốt hơn nếu tiêu đề đã được gửi. –  10:38:23 29/02/2016
11

Giải pháp dựa trên mod-rewrite:

Sử dụng mã sau trong htaccess sẽ tự động chuyển tiếp tất cả các yêu cầu http tới 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 http không có wwwwww của bạn đến phiên bản có 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 apache thấp hơn vì biến% {REQUEST_SCHEME} đã được thêm vào mod-rewrite kể từ ngày 2.4.

|
10

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 các độ 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 mới được thực hiện theo mặc định. Bạn phải chỉ định RewriteOptions InheritDownBeforechỉ thị (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 chứ không phải thư mục phía trên 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 có:

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]
|
  • 1
    Đây là khá nhiều điều mà mọi người trên Internet yêu cầu 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ở nên BẤT NGỜ hoặc Bạn không có quyền xem. đại loại vậy ... Tôi đang làm gì sai? Tôi chỉ muốn biết nếu bạn có bất kỳ ý tưởng nào trước khi tôi đăng câu hỏi về điều này. –  13:53:30 14/12/2018
  • 1
    Tôi đã gặp sự cố 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. –  10:19:46 02/07/2019
-1

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

  • 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]
    
|
-1

Một trong những đơ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

|
-1

Mã này phù hợp với tôi

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

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.