บังคับใช้ SSL / https โดยใช้. htaccess และ mod_rewrite


คำตอบ:


438

สำหรับ Apache คุณสามารถใช้mod_sslบังคับ SSL กับSSLRequireSSL Directive:

คำสั่งนี้ห้ามการเข้าถึงยกเว้นว่า HTTP ผ่าน SSL (เช่น HTTPS) เปิดใช้งานสำหรับการเชื่อมต่อปัจจุบัน สิ่งนี้มีประโยชน์มากภายในโฮสต์หรือไดเรกทอรีเสมือนที่เปิดใช้งาน SSL เพื่อป้องกันข้อผิดพลาดในการกำหนดค่าที่เปิดเผยเนื้อหาที่ควรได้รับการป้องกัน เมื่อคำสั่งนี้แสดงการร้องขอทั้งหมดจะถูกปฏิเสธซึ่งไม่ได้ใช้ SSL

สิ่งนี้จะไม่เปลี่ยนเส้นทางไปยัง https แม้ว่า หากต้องการเปลี่ยนเส้นทางให้ลองทำตามด้วยmod_rewriteในไฟล์. htaccess ของคุณ

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

หรือวิธีการต่าง ๆ ที่ได้รับที่

คุณยังสามารถแก้ปัญหานี้ได้จากภายใน PHP ในกรณีที่ผู้ให้บริการของคุณปิดการใช้งาน. htaccess (ซึ่งไม่น่าจะเกิดขึ้นตั้งแต่ที่คุณขอมาแต่ทว่า)

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
สิ่งนี้ดีมากในสถานการณ์ของเราเนื่องจากขณะนี้เรามีปริมาณการเข้าชม http และ https สำหรับพื้นที่ผู้ดูแลระบบของเราเราเพิ่งเปิดสคริปต์. htaccess ในขณะที่รักษา http ไซต์ที่เหลือ
Michael J. Calkins

1
เมื่อฉันใช้วิธี mod_rewrite ฉันได้รับการส่งไปยัง https แต่มีข้อผิดพลาด "หน้าไม่ได้เปลี่ยนเส้นทางอย่างถูกต้อง"
Czechnology

11
การติดตามผล: หากคุณมีปัญหาคล้ายกันให้ตรวจสอบเซิร์ฟเวอร์และตัวแปร HTTP ของคุณ หากเซิร์ฟเวอร์ของคุณใช้พรอกซีคุณอาจต้องการใช้%{HTTP:X-Forwarded-Proto}หรือ%{HTTP:X-Real-Port}ตัวแปรเพื่อตรวจสอบว่า SSL เปิดอยู่หรือไม่
Czechnology

8
หากคุณพบลูปการเปลี่ยนเส้นทางบนเซิร์ฟเวอร์ที่ใช้งานพร็อกซี่ ( CloudFlare , Openshift ) ให้ดูคำตอบสำหรับวิธีการแก้ปัญหาที่ใช้กับกรณีนี้ด้วย
raphinesse

4
@GTodorov - การลบพื้นที่ทำลาย rewriterule สำหรับฉัน จากความรู้ (จำกัด ) ของฉันเกี่ยวกับการเขียนRewriteRule <input-pattern> <output-url>ซ้ำไวยากรณ์คือ ดังนั้นพื้นที่จะต้องมีและ^เพียงแค่พูดว่า "ตรงกับ URL อินพุตทั้งหมด"
Sphinxxx

54

ฉันพบmod_rewriteวิธีแก้ปัญหาที่ทำงานได้ดีสำหรับเซิร์ฟเวอร์ทั้งที่ใช้งานร่วมและที่ไม่ได้ใช้งาน

หากคุณใช้CloudFlare, AWS Elastic Load Balancing, Heroku, OpenShiftหรือโซลูชัน Cloud / PaaS อื่น ๆ และคุณประสบปัญหาการเปลี่ยนเส้นทางโดยใช้การเปลี่ยนเส้นทาง HTTPS ปกติให้ลองใช้ตัวอย่างต่อไปนี้แทน

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]

ขอบคุณมาก! แต่อาจจะต้องเพิ่มเงื่อนไขการโพสต์? RewriteCond% {REQUEST_METHOD}! ^ POST $
Aleksej

@Aleksej จริงนี่เป็นการร้องขอ POST ที่ไม่เข้ารหัส แต่ฉันคิดว่านี่เป็นสิ่งที่ดี ด้วยวิธีนี้ผู้คนจะสังเกตเห็นว่าพวกเขากำลังทำอะไรผิด ฉันเดาว่าสิ่งที่ดีที่สุดคือการเปลี่ยนเส้นทางไปยังหน้าที่แจ้งให้พวกเขาทราบถึงวิธีการใช้บริการของคุณอย่างเหมาะสม
raphinesse

@raphinesse คุณรู้คำตอบของคำถามนี้: stackoverflow.com/questions/51951082/ หรือไม่
RRN

36

โซลูชั่น PHP

การยืมโดยตรงจากคำตอบที่ครอบคลุมมากของกอร์ดอนฉันทราบว่าคำถามของคุณระบุว่าเป็นหน้าเฉพาะในการบังคับใช้การเชื่อมต่อ 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>' );
    }
  }
}

จากนั้นใกล้กับส่วนบนของหน้าเหล่านี้ที่คุณต้องการบังคับให้เชื่อมต่อผ่าน PHP คุณสามารถrequire()ใช้ไฟล์ส่วนกลางที่มีฟังก์ชั่นที่กำหนดเองนี้ (และอื่น ๆ ) แล้วเรียกใช้forceHTTPS()ฟังก์ชัน

โซลูชัน HTACCESS / mod_rewrite

ฉันยังไม่ได้ใช้โซลูชันประเภทนี้เป็นการส่วนตัว (ฉันมักจะใช้โซลูชัน PHP เช่นเดียวกับข้างต้นเพราะเป็นเรื่องง่าย) แต่อย่างน้อยอาจเป็นการเริ่มต้นที่ดี

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]

จากความอยากรู้ว่าทำไมRewriteCond %{REQUEST_METHOD} !^POST$?
depoulo

12
เนื่องจากพารามิเตอร์ POST ไม่ได้ถูกเก็บไว้ในการเปลี่ยนเส้นทาง คุณสามารถละเว้นบรรทัดนั้นได้หากคุณต้องการให้แน่ใจว่าการส่ง POST ทั้งหมดนั้นปลอดภัย (การส่ง POST ที่ไม่ปลอดภัยใด ๆ จะถูกละเว้น)
ลุคสตีเวนสัน

@Lucanos - วิธีเขียน RewriteCond ที่ไม่บังคับให้เปลี่ยนเส้นทางไปยัง http หรือ https เมื่อ POST . htaccess ของฉันบังคับให้ใช้ HTTPS ในหน้าเฉพาะบางหน้าจากนั้นบังคับ HTTP ในส่วนที่เหลือ อย่างไรก็ตามในหน้า HTTPS มีแบบฟอร์มที่ส่งไปยังเว็บรูทของฉัน แบบฟอร์มระบุ URL การดำเนินการเป็น HTTPS อย่างไรก็ตามเนื่องจากเว็บรูทไม่ใช่หนึ่งในหน้าเว็บที่ระบุให้บังคับ HTTPS ดังนั้น. htaccess ของฉันจึงบังคับให้เปลี่ยนเส้นทางซึ่งหมายความว่าตัวแปร POST จะหายไป ฉันจะป้องกันการเปลี่ยนเส้นทางใน POST ได้อย่างไร
StackOverflow Newbie

1
@StackOverflowNewbie: บรรทัดRewriteCond %{REQUEST_METHOD} !^POST$ควรป้องกันการส่ง POST ไม่ให้ได้รับผลกระทบจากการเปลี่ยนเส้นทางเหล่านี้
ลุคสตีเวนสัน

ฉันชอบเวอร์ชั่น PHP นี้ มันจะดีกว่ามากเพราะถือว่า POST และจัดการได้ดีกว่าถ้าส่วนหัวได้ถูกส่งไปแล้ว
TheStoryCoder

10

Mod-rewrite based solution:

การใช้รหัสต่อไปนี้ใน htaccess จะส่งต่อคำร้องขอ http ทั้งหมดไปที่ https โดยอัตโนมัติ

RewriteEngine on

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

สิ่งนี้จะเปลี่ยนเส้นทางคำขอที่ไม่ใช่ wwwและwww http ไปยังรุ่นwwwของ https

โซลูชันอื่น (Apache 2.4 *)

RewriteEngine on

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

สิ่งนี้ใช้ไม่ได้กับ apache รุ่นที่ต่ำกว่าเนื่องจากมีการเพิ่มตัวแปร% {REQUEST_SCHEME} ลงใน mod-rewrite ตั้งแต่ 2.4


9

ฉันแค่อยากจะชี้ให้เห็นว่า Apache มีกฎการรับมรดกที่เลวร้ายที่สุดเมื่อใช้ไฟล์. htaccess หลายไฟล์ในระดับความลึกของไดเรกทอรี ข้อผิดพลาดที่สำคัญสองประการ:

  • เฉพาะกฎที่มีอยู่ในไฟล์. htaccess ที่ลึกที่สุดเท่านั้นที่จะถูกดำเนินการตามค่าเริ่มต้น คุณต้องระบุRewriteOptions InheritDownBeforeคำสั่ง (หรือคล้ายกัน) เพื่อเปลี่ยนสิ่งนี้ (ดูคำถาม)
  • รูปแบบจะถูกนำไปใช้กับเส้นทางของไฟล์ที่สัมพันธ์กับไดเรกทอรีย่อยและไม่ใช่ไดเรกทอรีด้านบนที่มีไฟล์. htaccess พร้อมกฎที่กำหนด (ดูการสนทนา)

ที่นี้หมายถึงการแก้ปัญหาโลกปัญหาในApache วิกิพีเดียไม่ไม่ทำงานถ้าคุณใช้ htaccess ไฟล์อื่น ๆ ในไดเรกทอรีย่อย ฉันเขียนเวอร์ชันดัดแปลงที่ทำ:

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

ง่ายและสะดวกเพียงเพิ่มสิ่งต่อไปนี้

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

นี่เป็นสิ่งที่ผู้คนทั่วอินเทอร์เน็ตบอกให้คุณทำเพื่อบังคับให้ https อย่างไรก็ตามทุกครั้งที่ฉันทำเช่นนั้นเว็บไซต์ทั้งหมดของฉันจะถูกห้ามหรือคุณไม่ได้รับอนุญาตให้ดู อะไรทำนองนั้น ... ฉันทำอะไรผิด ฉันแค่อยากรู้ว่าคุณมีความคิดใด ๆ ก่อนที่ฉันจะโพสต์คำถามเกี่ยวกับเรื่องนี้
THN

ฉันมีปัญหาที่คล้ายกันและฉันต้องใช้กฎกับไฟล์ https.conf ดูคำตอบของฉันด้านล่าง
Risteard

-1

รหัสนี้ใช้ได้สำหรับฉัน

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

-1

ง่าย ๆ :

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

แทนที่ URL ของคุณด้วย example.com


NO! URL ของไซต์ต้องเป็นแบบไดนามิก
Amir Savand

-1

เพียงแค่บังคับให้ SSL กับ Apache .htaccess คุณสามารถใช้ได้

SSLOptions +StrictRequire
SSLRequireSSL

สำหรับการเปลี่ยนเส้นทางคำตอบข้างต้นถูกต้อง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.