เปลี่ยนเส้นทางไปยัง SSL เฉพาะเมื่อเบราว์เซอร์รองรับ SNI


20

ฉันมี Apache 2.2 พร้อม mod_ssl และไซต์จำนวนมากใน HTTPS บน IP / พอร์ตเดียวกันกับ VirtualHosting ดังนั้นไคลเอ็นต์ต้องสนับสนุน SNI เพื่อเชื่อมต่อกับโฮสต์เสมือนเหล่านั้น

ฉันต้องการกำหนดค่าเซิร์ฟเวอร์ของฉันด้วยวิธีต่อไปนี้:

เมื่อผู้ใช้พิมพ์ www.dummysite.com และเบราว์เซอร์ของเขารองรับ SNI (การระบุชื่อเซิร์ฟเวอร์) คำขอ HTTP ใด ๆ จะถูกเปลี่ยนเส้นทางไปยังhttps://ที่ซึ่งมีการส่งส่วนหัว HSTS แต่ถ้าเบราว์เซอร์ไม่รองรับ SNI ดังนั้นคำขอจะถูกให้บริการโดย HTTP

กฎดังกล่าวข้างต้นตามที่เป็นจริงเป็นกฎทางเลือกสำหรับคนที่ยังคงใช้เบราว์เซอร์เก่าเนื่องจาก Mozilla และ Chrome ไม่มีปัญหานี้เพียงเพื่อหลีกเลี่ยงการปล่อยให้ผู้ใช้เหล่านี้ออกจากเว็บไซต์

ฉันต้องการเปลี่ยนเส้นทางนี้ในระดับการกำหนดค่า Apache อาจมีตัวกรองในตัวแทนผู้ใช้ ฉันไม่ต้องการสัมผัสแอปพลิเคชั่นที่ทำงานอยู่ยกเว้นว่าจะไม่มีการอ้างอิง http: // โดยตรง (ไม่เช่นนั้นจะมีคำเตือนด้านความปลอดภัย)

[แก้ไข] (ในขณะที่การแก้ไขคำถามที่ฉันลืมคำถาม): สิ่งที่เป็นรายชื่อของตัวแทนผู้ใช้ SNI ที่เปิดใช้งานเพื่อเปลี่ยนเส้นทาง?

คำตอบ:


20

เนื่องจาก SNI เกิดขึ้นระหว่างการจับมือ SSL / TLS จึงไม่สามารถตรวจพบการสนับสนุนเบราว์เซอร์เมื่อไคลเอ็นต์เชื่อมต่อกับ HTTP

ดังนั้นคุณพูดถูก ตัวกรองตัวแทนผู้ใช้เป็นวิธีเดียวที่จะทำเช่นนี้

คำถามใหญ่คือว่าคุณต้องการที่จะดำเนินการในบัญชีดำกับเบราว์เซอร์ที่คุณรู้ว่าจะไม่ฟัง SNI หรือรายการที่ปลอดภัยของเบราว์เซอร์ที่รู้จักกันเพื่อสนับสนุน อุปกรณ์ที่คลุมเครือหรือใหม่ไม่สามารถใช้งานเว็บไซต์ได้ดูเหมือนเป็นดีลเลอร์เบรกเกอร์ดังนั้นฉันจึงบอกว่าบัญชีขาวอาจเป็นตัวเลือกที่ดีกว่า

ใน HTTP ของคุณ<VirtualHost>:

# Internet Explorer 7, 8, 9, on Vista or newer
RewriteCond %{HTTP_USER_AGENT} MSIE\s7.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s8.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s9.*Windows\sNT\s6 [OR]
# Chrome on Windows, Mac, Linux
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s6.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Macintosh.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Linux.*Chrome [OR]
# Firefox - we'll just make the assumption that all versions in the wild support:
RewriteCond %{HTTP_USER_AGENT} Gecko.*Firefox
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

นี่คือตัวเลือกบัญชีดำด้วย - โปรดทราบว่านี่จะเสี่ยงต่อการส่งไคลเอ็นต์ที่ไม่ได้ใช้ SNI ไปยังไซต์ที่ต้องการ SNI แต่ในทางกลับกันจะส่งผู้ใช้ใหม่อย่าง IE 10 ไปทางขวา สถานที่:

# IE 6
RewriteCond %{HTTP_USER_AGENT} !MSIE\s6
# Windows XP/2003
RewriteCond %{HTTP_USER_AGENT} !Windows\sNT\s5
# etc etc
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

มีเบราว์เซอร์จำนวนมากออกมี ฉันค่อนข้างหลวมกับการแสดงออกและยังไม่ได้ครอบคลุมเบราว์เซอร์มากมาย - นี่อาจกลายเป็นฝันร้ายที่จะรักษา

ตัวเลือกใดก็ได้ที่คุณเลือก .. ขอให้โชคดี!


1
ที่ดี! ฉันทดสอบกับ Opera Mobile (ซึ่งเป็นไปตาม SNI แต่ไม่ได้อยู่ในรายการ) และไม่เปลี่ยนเส้นทาง ด้วย Firefox ของฉันมันเปลี่ยนเส้นทาง!
usr-local-ΕΨΗΕΛΩΝ

6
ผมขอแนะนำให้ modularizing แก้ปัญหานี้ด้วยการสั่ง BrowserMatch จาก mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html ใช้ BrowserMatch เพื่อตั้งค่าตัวแปรสภาพแวดล้อมรองรับ_sni = y จากนั้นเขียน RewriteCond% {ENV :support_sni} = y ด้วยวิธีนี้คุณสามารถใช้ตรรกะการตรวจหา SNI ซ้ำสำหรับ RewriteRules อื่น ๆ ที่คุณอาจมี
200_success

@ 200_ ประสบความสำเร็จเป็นความคิดที่ดี!
เชน Madden

8

ทางออกของฉันคือ:

  # Test if SNI will work and if not redirect to too old browser page
  RewriteCond %{HTTPS} on
  RewriteCond %{SSL:SSL_TLS_SNI} =""
  RewriteRule ^ http://www.example.com/too-old-browser [L,R=307]

หากเบราว์เซอร์เก่าที่ไม่มี SNI พยายามเข้าถึงhttps://www.example.com/ * จากนั้นเบราว์เซอร์จะโยนข้อผิดพลาดบนเบราว์เซอร์ก่อนซึ่งจะไม่สามารถหลีกเลี่ยงได้ตั้งแต่จนกระทั่ง apache ตอบกลับไปยังเบราว์เซอร์ที่ไม่ใช่ SNI เว็บไซต์ที่ต้องการ จากนั้นจะเปลี่ยนเส้นทางไปยังหน้าเว็บที่แจ้งให้ผู้ใช้ทราบว่าเบราว์เซอร์ของพวกเขานั้นเก่าเกินไป (ตราบใดที่ผู้ใช้คลิกเว็บไซต์ต่อไป)

และสำหรับผู้ใช้ที่มีเบราว์เซอร์ใหม่ที่ฉันมี

  #Test if new browser and if so redirect to https
  #new browser is not MSIE 5-8, not Android 0-3
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP_USER_AGENT} !MSIE\ [5-8]
  RewriteCond %{HTTP_USER_AGENT} !Android.*(Mobile)?\ [0-3]
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

ซึ่งไม่รวมเบราว์เซอร์เก่าส่วนใหญ่รวมถึง MSIE 5-8 บน Vista (9+ เป็น Vista / 7 เท่านั้นดังนั้นจึงสนับสนุน SNI) ไม่ใช่ 100% (Symbian ถูกละเว้น ฯลฯ ) แต่ควรใช้ได้กับคนส่วนใหญ่ ชนกลุ่มน้อยยังคงสามารถเลือกที่จะยอมรับข้อผิดพลาดใบรับรอง


3

เท่าที่ฉันทราบไม่มีวิธีที่ดีในการทำเช่นนี้ - คุณสามารถใช้กฎ mod_rewriteหรือคล้ายกันตามเงื่อนไขตามUser-agentส่วนหัว แต่จะต้องอยู่บน vhost ที่ไม่ใช่ SSL: หากเบราว์เซอร์ไม่สนับสนุน SNI และไปที่https://ไซต์ที่มีการรักษาความปลอดภัย ( ) มันจะได้รับพฤติกรรมอาปาเช่แบบเก่าของ"นี่คือใบรับรอง SSL ตัวแรกที่ฉันเชื่อมโยงกับที่อยู่ IP นั้น - หวังว่าจะเป็นสิ่งที่คุณต้องการ!" - หากไม่ใช่ใบรับรองเบราว์เซอร์คาดหวังว่าคุณจะได้รับข้อความแสดงข้อผิดพลาดเกี่ยวกับชื่อโฮสต์ที่ไม่ตรงกัน

โดยทั่วไปหมายความว่าผู้คนต้องเข้าสู่หน้าเว็บคั่นกลางที่ไม่ใช่ SSL ซึ่งจะเปลี่ยนเส้นทาง - อาจเปิดเผยข้อมูลใด ๆ ที่พวกเขากำลังส่งในคำขอของพวกเขา นี่อาจเป็นหรือไม่เป็นตัวจัดการข้อตกลง (คุณบอกว่าคุณกำลังจะส่งพวกเขาไปยังไซต์ที่ไม่ใช่ SSL อย่างไรก็ตามหากพวกเขาไม่สนับสนุน SNI ดังนั้นฉันคิดว่าคุณไม่สนใจเรื่องความปลอดภัยมากนัก การออกแบบระบบที่มีความต้องการ SSL เป็นเลเยอร์การเข้ารหัสหรือการพิสูจน์ตัวตนฉันจะค่อนข้างยืนกรานเกี่ยวกับเรื่องนี้มากกว่า ... )

ไม่มีสิ่งใดที่จะห้ามไม่ให้ใครบางคนทำบุ๊กมาร์กไซต์ที่ปลอดภัยแม้ว่า - และหากพวกเขาใช้บริการบุ๊คมาร์คที่ใช้ร่วมกันหรือคืนค่าบุ๊กมาร์กของพวกเขาไปยังเครื่องที่เว็บเบราว์เซอร์ไม่สนับสนุน SNI .


1

ฉันถูกล่อลวงให้แก้หนึ่งในสามวิธีนี้:

  1. RewriteRuleขึ้นอยู่กับUser-Agentส่วนหัว
  2. โหลด https: // URI ใน<SCRIPT>แท็กบน VHost ที่ไม่ใช่ค่าเริ่มต้น หากการโหลดสำเร็จจะเป็นบิตของ JS ที่โหลดทั้งหน้าภายใต้ HTTPS
  3. สอนให้ผู้เยี่ยมชมของฉันใช้บางอย่างเช่น HTTPS ทุกที่ถ้านี่เป็นเรื่องสำคัญสำหรับพวกเขาบังคับให้ HTTPS บนหน้าเว็บที่ควรจะต้องใช้และหวังว่าทุกอย่างจะได้ผลในที่สุด

ในบรรดาสิ่งเหล่านี้ฉันชอบที่ดีที่สุด # 2 แต่นั่นเกี่ยวข้องกับการแก้ไขโค้ดของไซต์ของคุณ


0

สำหรับทุกคนที่ต้องการมัน

หากคุณมีหลายโฮสต์และต้องการให้เปิดใช้งาน SSL ทั้งหมดใน VirtualHosting (และคุณซื้อใบรับรองสำหรับแต่ละรายการ) ให้ลองใหม่ mod_djechelon_ssl

$ cat /etc/apache2/mod_djechelon_ssl.conf 
RewriteEngine on
# Internet Explorer 7, 8, 9, on Vista or newer
RewriteCond %{HTTP_USER_AGENT} MSIE\s7.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s8.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s9.*Windows\sNT\s6 [OR]
# Chrome on Windows, Mac, Linux
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s6.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Macintosh.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Linux.*Chrome [OR]
# Firefox - we'll just make the assumption that all versions in the wild support:
RewriteCond %{HTTP_USER_AGENT} Gecko.*Firefox [OR]
#Safari iThing
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPhone.*Safari [OR]
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPod.*Safari [OR]
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPad.*Safari [OR]
RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [R=permanent,L]

การใช้งาน:

<VirtualHost ip:80>
ServerName www.yourhost.com

Include /path/to/mod_djechelon_ssl.conf

[plain old Apache directives]
</VirtualHost>

<VirtualHost ip:443>
ServerName www.yourhost.com

[SSL-related directives]

[Copy and paste directives from above host]
</VirtualHost>

0

ตามที่ฉันโพสต์ที่นี่คุณสามารถทดสอบได้เฉพาะกับการสนับสนุน SNI ก่อนที่จะกำหนด นั่นคือคุณไม่สามารถบังคับให้ผู้ใช้เข้าสู่ SNI HTTPS แล้วถอยกลับหากพวกเขาไม่สนับสนุนเพราะพวกเขาจะได้รับข้อผิดพลาดเช่นนี้ (จาก Chrome บน Windows XP) โดยไม่มีวิธีดำเนินการ

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

คุณสามารถตรวจหาการสนับสนุน SNI ผ่าน:

  1. สคริปต์ระยะไกล
    จากหน้า HTTP ธรรมดาของคุณโหลด<script>จากเซิร์ฟเวอร์ SNI HTTPS ปลายทางของคุณและหากสคริปต์โหลดและทำงานอย่างถูกต้องคุณจะรู้ว่าเบราว์เซอร์รองรับ SNI

  2. ข้ามโดเมน AJAX ( ธ )
    คล้ายกับตัวเลือกที่ 1 คุณอาจจะลองดำเนินการคำขอ AJAX ข้ามโดเมนจากหน้า HTTP เพื่อ HTTPS แต่ทราบว่า ธ ได้สนับสนุนเบราว์เซอร์ จำกัด เฉพาะ

  3. Sniff the user-agent
    นี่น่าจะเป็นวิธีที่เชื่อถือได้น้อยที่สุดและคุณจะต้องตัดสินใจว่าจะมีบัญชีดำของเบราว์เซอร์ (และระบบปฏิบัติการ) ที่รู้จักว่าไม่รองรับหรือเป็นรายการที่อนุญาตของระบบที่รู้จัก

    เรารู้ว่าทุกรุ่นของ IE, Chrome & Opera บน Windows XP และด้านล่างไม่รองรับ SNI ดูCanIUse.com สำหรับรายการเบราว์เซอร์ที่รองรับทั้งหมด

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