Làm cách nào tôi có thể buộc người dùng truy cập trang của mình qua HTTPS thay vì HTTP?


137

Tôi chỉ có một trang mà tôi muốn buộc phải truy cập dưới dạng trang HTTPS (PHP trên Apache). Làm thế nào để tôi làm điều này mà không làm cho toàn bộ thư mục yêu cầu HTTPS? Hoặc, nếu bạn gửi biểu mẫu đến trang HTTPS từ trang HTTP, liệu nó có gửi nó bằng HTTPS thay vì HTTP không?

Đây là ví dụ của tôi:

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

Tôi muốn nó chỉ được truy cập thông qua:

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

Chắc chắn, tôi có thể đặt tất cả các liên kết đến trang này chỉ vào phiên bản HTTPS, nhưng điều đó không ngăn được kẻ ngốc truy cập thông qua HTTP nhằm mục đích ...

Một điều tôi nghĩ là đặt một chuyển hướng trong tiêu đề của tệp PHP để kiểm tra để chắc chắn rằng họ đang truy cập phiên bản HTTPS:

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

Nhưng đó không phải là cách đúng đắn, phải không?



3
Có bất kỳ lý do tại sao bạn không chỉ yêu cầu SSL cho tất cả các trang?
Tahaan

Câu trả lời:


177

Cách tôi đã thực hiện trước đây về cơ bản giống như những gì bạn đã viết, nhưng không có bất kỳ giá trị được mã hóa cứng nào:

if ($ _ SERVER ["HTTPS"]! = "bật")
{
    tiêu đề ("Vị trí: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    lối ra();
}

15
Bạn đã quên gọi exit () để đảm bảo tập lệnh thoát sau khi chuyển hướng. Tôi thường gói nó trong một hàm gọi là allowSSL (). Tôi có thể gọi cái này ở đầu bất kỳ trang nào tôi muốn được mã hóa.
Jesse Weigert

31
Thay đổi nếu được (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")để sửa các thông báo PHP.
dave1010

Các $_SERVER[]biến không thay đổi / dễ bị người dùng can thiệp?
Arian Faurtosh

@ArianFaurtosh nguồn?
Giăng

3
@ArianFaurtosh một số được trích xuất từ ​​các tiêu đề của khách hàng, như HTTP_X_FORWARDEDvà có thể bị thao túng, nhưng một số khác thích HTTPShoặc SERVER_PORTđược đặt trực tiếp từ máy chủ web và thường phải an toàn.
Mahn

46

Bạn có thể làm điều đó với một lệnh và mod_rewrite trên Apache:

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

Bạn có thể làm cho Vị trí thông minh hơn theo thời gian bằng cách sử dụng các biểu thức thông thường nếu bạn muốn.


6
Bạn sẽ đặt cái này ở đâu? tập tin .htaccess?

1
Không REQUEST_URI không bao gồm "chuỗi truy vấn" (như? Page = 1 & id = 41, v.v.)? Đó là những gì tài liệu apache nói ... Vì vậy, nếu tôi cố gắng truy cập trang web.com / index.php? Page = 1 & id = 12, tôi sẽ được chuyển hướng trang web.com / index.php
Rolf

2
Từ tài liệu apache: REQUEST_URI Thành phần đường dẫn của URI được yêu cầu, chẳng hạn như "/index.html". Điều này đáng chú ý loại trừ chuỗi truy vấn có sẵn dưới dạng biến của chính nó có tên QUERY_STRING. Vì vậy, bạn cần thêm QUERY_STRING sau REQUEST_URI
Rolf

2
Sau đó, bạn cũng cần thêm đoạn [R] để chuyển hướng
Rolf

40

Bạn nên buộc khách hàng luôn yêu cầu HTTPS với các tiêu đề 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();
}

Xin lưu ý rằng HSTS được hỗ trợ trong hầu hết các trình duyệt hiện đại, nhưng không phổ biến. Do đó, logic ở trên sẽ chuyển hướng thủ công người dùng bất kể hỗ trợ nếu họ kết thúc bằng HTTP và sau đó đặt tiêu đề HSTS để các yêu cầu khách tiếp theo sẽ được trình duyệt chuyển hướng nếu có thể.


Tôi ngạc nhiên khi không có câu trả lời nào khác bao gồm tiêu đề này, nó khá quan trọng ... có bất kỳ cạm bẫy nào khi kết hợp cả hai không?
keisar

Không ... bạn chắc chắn có thể đặt tiêu đề đó bằng mọi cách nếu bạn luôn muốn HTTPS. Nó chỉ là loại dự phòng để đặt nó trước và sau khi bạn thực hiện chuyển hướng. Tôi cũng đã sửa đổi phản hồi của mình ở trên để giải thích chính xác hơn khả năng tương thích.
Jacob Swartwood

1
(Xác định lại nhận xét ban đầu) Tôi không nhận thấy yêu cầu cụ thể của "chỉ một trang". HSTS sẽ áp dụng cho tất cả các trang; Câu trả lời của tôi là không chính xác.
Jacob Swartwood

4
FYI, RFC 6797 tiêu chuẩn phần 7.2 cho biết "Máy chủ HSTS KHÔNG PHẢI bao gồm trường tiêu đề STS trong các phản hồi HTTP được truyền tải qua vận chuyển không an toàn." vì vậy không cần gửi nó khi yêu cầu là http thông thường, nên bỏ qua nếu trình duyệt tuân theo tiêu chuẩn.
Frank Forte

1
@mark nếu có MITM và trang web của bạn không có tiêu đề này, bạn có thể cho phép một phiên bao gồm để truy cập http và mọi người nhập thông tin của họ và họ có thể sẽ không thông báo và chuyển hướng sẽ không giúp đỡ (người đàn ông trong giữa sẽ kết nối với trang web thông qua https và hiển thị dưới dạng http). Sử dụng tiêu đề này sẽ buộc HTTPS ở phía máy khách. Điều này đặc biệt quan trọng do lỗ hổng bảo mật WiFi WPA2 gần đây.
Rudiger

19

Tôi vừa tạo một tệp .htaccess và thêm:

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

Đơn giản !


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

8

Phải làm một cái gì đó như thế này khi chạy phía sau một bộ cân bằng tải. Mũ lưỡi trai 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;
    }
}

6

Cách thức của 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);
}

Cách mod_rewrite của Apache:

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

Tôi thích cách PHP hơn vì có những trường hợp tôi muốn ghi đè yêu cầu về SSL. Ví dụ: quyền truy cập cục bộ vào API và những thứ như tự động cấu hình của Mozilla Thunderbird, v.v.
Jay

Phương pháp PHP hoạt động hoàn hảo đối với tôi, rất khuyến khích.
Moxet

5

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

Đôi khi bạn có thể cần đảm bảo rằng người dùng đang duyệt trang web của bạn qua kết nối bảo mật. Một cách dễ dàng để luôn chuyển hướng người dùng đến kết nối an toàn (https: //) có thể được thực hiện bằng tệp .htaccess chứa các dòng sau:

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

Xin lưu ý rằng .htaccess phải được đặt trong thư mục chính của trang web.

Trong trường hợp bạn muốn buộc HTTPS cho một thư mục cụ thể, bạn có thể sử dụng:

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

Tệp .htaccess phải được đặt trong thư mục mà bạn cần buộc HTTPS.


5

Ok .. Bây giờ có hàng tấn công cụ này nhưng không ai thực sự hoàn thành câu hỏi "An toàn". Đối với tôi, thật là kỳ quặc khi sử dụng một cái gì đó không an toàn.

Trừ khi bạn sử dụng nó làm mồi nhử.

Việc truyền bá $ _SERVER có thể được thay đổi theo ý muốn của một người biết cách.

Ngoài ra, như Sazzad Tushar Khan và thebigjc đã nói rằng bạn cũng có thể sử dụng omeaccess để làm điều này và có rất nhiều câu trả lời ở đây có chứa nó.

Chỉ cần thêm:

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

đến cuối những gì bạn có trong .httaccess của bạn và đó là điều đó.

Tuy nhiên, chúng tôi không an toàn như chúng tôi có thể với 2 công cụ này.

Phần còn lại là đơn giản. Nếu có thuộc tính bị thiếu, tức là ...

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

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


Cũng nói rằng bạn đã cập nhật tệp omeaccess của bạn và bạn kiểm tra:

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

Có rất nhiều biến số bạn có thể kiểm tra tức là ..

HOST_URI (Nếu có các thuộc tính tĩnh về nó để kiểm tra)

HTTP_USER_AGENT (Cùng giá trị phiên khác nhau)

Vì vậy, tất cả những gì tôi nói là không chỉ giải quyết cho cái này hay cái khác khi câu trả lời nằm trong một sự kết hợp.

Để biết thêm thông tin viết lại của Oleaccess, hãy xem tài liệu-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Một số ngăn xếp ở đây -> Buộc SSL / https sử dụng .htaccess và mod_rewrite

Lấy URL đầy đủ của trang hiện tại (PHP)
để đặt tên cho một cặp vợ chồng.


2
nhưng bây giờ tôi nhận được lỗi sau : ERR_TOO_MANY_REDIRECTS. Làm thế nào để tôi sửa lỗi này?
Pathros

3

Sử dụng $_SERVER['HTTPS']để biết đó có phải là SSL hay không và chuyển hướng đến đúng nơi nếu không.

Và hãy nhớ rằng, trang hiển thị biểu mẫu không cần phải được cung cấp qua HTTPS, đó là URL đăng lại cần nó nhất.

Chỉnh sửa : có, như được chỉ ra dưới đây, tốt nhất là có toàn bộ quá trình trong HTTPS. Nó yên tâm hơn nhiều - tôi đã chỉ ra rằng bài viết là phần quan trọng nhất. Ngoài ra, bạn cần lưu ý rằng mọi cookie được đặt là an toàn, vì vậy chúng sẽ chỉ được gửi qua SSL. Giải pháp mod_rewrite cũng rất tiện lợi, tôi đã sử dụng nó để bảo mật rất nhiều ứng dụng trên trang web của riêng tôi.


Đúng là bản thân biểu mẫu không cần phải là https, mặc dù đó là ý tưởng tốt cho phần lớn những người không biết điều này. Nếu họ chuẩn bị gửi biểu mẫu và nhận thấy rằng biểu tượng khóa không có ở đó, họ có thể nhầm tưởng rằng biểu mẫu đó không an toàn.
Graeme Perrow

1
@Graeme: ngoài ra không ai có thể chắc chắn rằng biểu mẫu sẽ được gửi qua https. Toàn bộ biểu mẫu (được hiển thị qua http) có thể là giả mạo, gửi đến một trang web Cleartext không xác định hoặc http. Https không chỉ là về mã hóa, nó còn xác thực máy chủ.
Olaf Kock

3

sử dụng 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]

1

Không trộn HTTP và HTTPS trên cùng một trang. Nếu bạn có một trang biểu mẫu được cung cấp qua HTTP, tôi sẽ lo lắng về việc gửi dữ liệu - Tôi không thể xem liệu việc gửi qua HTTPS hay HTTP mà không thực hiện Xem nguồn và tìm kiếm nó.

Việc cung cấp biểu mẫu qua HTTPS cùng với liên kết gửi không phải là một thay đổi lớn cho lợi thế.


1

Nếu bạn sử dụng Apache hoặc một cái gì đó như LiteSpeed, hỗ trợ các tệp .htaccess, bạn có thể làm như sau. Nếu bạn chưa có tệp .htaccess, bạn nên tạo tệp .htaccess mới trong thư mục gốc của bạn (thường là nơi tệp index.php của bạn được đặt). Bây giờ thêm các dòng này làm quy tắc viết lại đầu tiên trong .htaccess của bạn:

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

Bạn chỉ cần hướng dẫn "RewriteEngine On" một lần trong .htaccess của bạn cho tất cả các quy tắc viết lại, vì vậy nếu bạn đã có nó, chỉ cần sao chép dòng thứ hai và thứ ba.

Tôi hi vọng cái này giúp được.


Đây là những gì làm việc cho tôi và những gì tôi đang sử dụng trong các tập lệnh riêng của mình trên Khung giống như Zend 2 - Tôi không hiểu downvote.
Antonio

Có lẽ bạn đã bị từ chối vì câu trả lời gần giống như câu trả lời này từ @MatHatrik đã được đăng hơn một năm trước?
Héo

1

Sử dụng điều này là không đủ:

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

Nếu bạn có bất kỳ nội dung http nào (như nguồn hình ảnh http bên ngoài), trình duyệt sẽ phát hiện mối đe dọa có thể. Vì vậy, hãy chắc chắn rằng tất cả các ref và src bên trong mã của bạn là https


1

Tôi đã trải qua nhiều giải pháp với việc kiểm tra trạng thái của $ _SERVER [HTTPS] nhưng có vẻ như nó không đáng tin cậy vì đôi khi nó không được đặt hoặc đặt thành bật, tắt, v.v. khiến tập lệnh chuyển hướng vòng lặp bên trong.

Đây là giải pháp đáng tin cậy nhất nếu máy chủ của bạn hỗ trợ $ _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;
}

Xin lưu ý rằng tùy thuộc vào cài đặt của bạn, máy chủ của bạn có thể không hỗ trợ $ _SERVER [SCRIPT_URI] nhưng nếu có, đây là tập lệnh tốt hơn để sử dụng.

Bạn có thể kiểm tra tại đây: Tại sao một số cài đặt PHP có $ _SERVER ['SCRIPT_URI'] và những người khác thì không


1

Đối với những người sử dụng IIS, thêm dòng này vào web.config sẽ giúp:

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

Một tập tin ví dụ đầy đủ

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

Câu hỏi đặc biệt hỏi về Apache, không phải IIS.
Quentin

1
A) nó không được gắn thẻ apache. Apache được đo giữa các trích dẫn. B) đó là một câu hỏi chung chung không liên quan gì đến apache nói chung. Nó áp dụng cho nhiều máy chủ web hỗ trợ php
Tschallacka

0

Bạn không nên vì lý do bảo mật. Đặc biệt là nếu cookie được chơi ở đây. Nó để bạn mở rộng cho các cuộc tấn công phát lại dựa trên cookie.

Dù bằng cách nào, bạn nên sử dụng các quy tắc điều khiển Apache để điều chỉnh nó.

Sau đó, bạn có thể kiểm tra HTTPS có được bật không và chuyển hướng khi cần thiết.

Bạn chỉ nên chuyển hướng đến trang trả tiền bằng cách sử dụng POST FORM (không lấy) và truy cập vào trang mà không có POST nên được chuyển trở lại các trang khác. (Điều này sẽ bắt những người chỉ nhảy nóng.)

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

Là một nơi tốt để bắt đầu, xin lỗi vì không cung cấp thêm. Nhưng bạn thực sự nên đẩy mọi thứ qua SSL.

Nó bảo vệ quá mức, nhưng ít nhất bạn có ít lo lắng hơn.


0

có lẽ điều này có thể giúp bạn, đó là cách tôi đã làm cho trang web của mình, nó hoạt động như một cơ duyên:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

if (!strstr($protocol, 'https')){
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

0

Nếu bạn muốn sử dụng PHP để làm điều này thì cách này thực sự hiệu quả với tôi:


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

Nó kiểm tra biến HTTPS trong mảng siêu lớp $ _SERVER để xem liệu nó có bằng với trên trên không. Nếu biến không bằng trên.


-1

Tôi đã sử dụng kịch bản này và nó hoạt động tốt thông qua trang web.

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

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

Điều đó thật dễ dàng.

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.