Redirect ke SSL hanya jika browser mendukung SNI

20

Saya memiliki Apache 2.2 dengan mod_ssl dan banyak situs di HTTPS pada IP / port yang sama dengan VirtualHosting, jadi klien harus mendukung SNI untuk terhubung ke host virtual tersebut.

Saya ingin mengonfigurasi server saya dengan cara berikut:

Ketika pengguna mengetikkan www.dummysite.com dan browsernya mendukung SNI (Server Name Indication), setiap permintaan HTTP dialihkan ke https://tempat header HSTS dikirim. Tetapi jika browser tidak mendukung SNI maka permintaan dilayani oleh HTTP.

Aturan di atas, dinyatakan apa adanya, sebenarnya adalah aturan fallback untuk orang-orang yang masih menjalankan browser lama, karena Mozilla dan Chrome tidak memiliki masalah ini, hanya untuk menghindari meninggalkan para pengguna ini dari situs.

Saya ingin melakukan pengalihan ini di tingkat konfigurasi Apache, mungkin dengan filter pada agen pengguna. Saya tidak ingin menyentuh aplikasi yang sedang berjalan kecuali memastikan tidak ada http langsung: // referensi ada (jika tidak mereka menyiratkan peringatan keamanan)

[Sunting] (ketika mengedit pertanyaan saya lupa yang pertanyaan): apa daftar agen pengguna SNI-enabled untuk mengarahkan?

usr-local-ΕΨΗΕΛΩΝ
sumber

Jawaban:

20

Karena SNI terjadi selama jabat tangan SSL / TLS, tidak mungkin untuk mendeteksi dukungan browser ketika klien terhubung ke HTTP.

Jadi kamu benar; filter agen-pengguna adalah satu-satunya cara untuk melakukan ini.

Pertanyaan besarnya adalah apakah Anda ingin mengambil tindakan terhadap daftar hitam terhadap peramban yang Anda tahu tidak akan mendengarkan SNI, atau daftar putih peramban yang dikenal mendukungnya. Perangkat tidak jelas atau baru yang tidak dapat menggunakan situs ini tampak seperti pemecah kesepakatan, jadi saya akan mengatakan daftar putih mungkin merupakan opsi yang lebih baik.

Di HTTP Anda <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]

Inilah opsi daftar hitam juga - perlu diingat bahwa ini berisiko mengirim klien yang tidak menggunakan SNI ke situs yang membutuhkan SNI, tetapi di sisi lain, akan mengirim pengguna sesuatu yang baru seperti IE 10 ke kanan. tempat:

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

Ada banyak browser di luar sana. Saya sudah sangat longgar dengan ekspresi dan belum menutupi banyak browser - ini bisa berubah menjadi mimpi buruk untuk dipertahankan.

Opsi mana pun yang Anda pilih .. semoga berhasil!

Shane Madden
sumber
1
Besar! Saya menguji dengan Opera Mobile (yang sesuai SNI tetapi tidak ada dalam daftar) dan tidak mengarahkan ulang. Dengan Firefox saya, itu mengarahkan ulang!
usr-local-ΕΨΗΕΛΩΝ
6
Saya sarankan memodulasi solusi ini dengan direktif BrowserMatch dari mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html . Gunakan BrowserMatch untuk mengatur variabel lingkungan yang support_sni = y, lalu tulis RewriteCond% {ENV: support_sni} = y. Dengan begitu, Anda dapat menggunakan kembali logika pendeteksian SNI untuk peraturan RewriteR lainnya yang mungkin Anda miliki.
200_sukses
@ 200_sukses Ide bagus!
Shane Madden
8

Solusi saya adalah ini:

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

Jika peramban lama tanpa SNI mencoba mengakses https://www.example.com/ * maka peramban itu akan melakukan kesalahan pada peramban terlebih dahulu, yang tidak dapat dihindari sejak sampai apache membalas peramban non-SNI, ia tidak tahu. situs mana yang diminta. Kemudian ia dialihkan ke halaman yang memberi tahu pengguna bahwa browser mereka terlalu lama (selama klik pengguna berlanjut ke situs web).

Dan untuk pengguna dengan browser baru yang saya miliki

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

Itu tidak termasuk sebagian besar browser lama, termasuk beberapa seperti MSIE 5-8 pada Vista (9+ hanya Vista / 7 jadi mendukung SNI). Ini bukan 100% (symbian diabaikan dll.) Tetapi harus bekerja untuk mayoritas. Minoritas masih dapat memilih untuk menerima kesalahan sertifikat.

malc_b
sumber
3

Sejauh yang saya tahu ada tidak benar-benar cara yang baik untuk melakukan hal ini - Anda dapat menggunakan aturan mod_rewrite atau serupa bersyarat berdasarkan User-agentheader, tetapi harus berada pada vhost NON-SSL: Jika browser tidak mendukung SNI dan masuk ke situs aman ( https://) itu akan mendapatkan perilaku Apache jadul dari "Ini sertifikat SSL pertama yang saya kaitkan dengan alamat IP itu - Semoga itu yang Anda inginkan!" - Jika itu bukan sertifikat yang diharapkan peramban Anda akan berakhir dengan pesan kesalahan tentang ketidakcocokan nama host.

Ini pada dasarnya berarti orang harus membuka halaman pengantar non-SSL yang akan mengarahkan mereka - mungkin mengekspos data apa pun yang mereka kirim dalam permintaan mereka. Ini mungkin atau mungkin bukan pelanggar kesepakatan (Anda mengatakan Anda akan mengirimnya ke situs non-SSL jika mereka tidak mendukung SNI, jadi saya menganggap Anda tidak terlalu peduli dengan keamanan. merancang sistem yang membutuhkan SSL sebagai lapisan enkripsi atau otentikasi saya akan sedikit lebih mendesak tentang hal itu ...)

Namun, tidak ada yang menghentikan seseorang untuk mem-bookmark situs yang aman - dan jika mereka menggunakan layanan bookmark bersama atau mengembalikan bookmark mereka ke mesin di mana browser web tidak mendukung SNI, mereka kembali ke kasus Potensi-untuk-SSL-Kesalahan. .

voretaq7
sumber
1

Saya akan tergoda untuk memecahkan ini satu dari tiga cara:

  1. RewriteRuleberdasarkan User-Agentheader.
  2. Muat https: // URI dalam <SCRIPT>tag di VHost non-default; jika memuat berhasil, itu sedikit JS yang memuat ulang seluruh halaman di bawah HTTPS.
  3. Ajari pengunjung saya untuk menggunakan sesuatu seperti HTTPS Everywhere jika ini merupakan prioritas bagi mereka, paksa HTTPS pada halaman di mana seharusnya diperlukan, dan berharap semuanya berhasil pada akhirnya.

Dari jumlah tersebut, saya pribadi paling suka # 2, tetapi itu melibatkan memodifikasi kode situs Anda.

BMDan
sumber
0

Hanya untuk siapa saja yang membutuhkannya.

Jika Anda memiliki banyak host dan ingin semuanya diaktifkan dengan SSL di VirtualHosting (dan Anda membeli sertifikat untuk masing-masing) coba yang baru 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]

Pemakaian:

<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>
usr-local-ΕΨΗΕΛΩΝ
sumber
0

Seperti yang saya posting di sini , Anda hanya dapat menguji dukungan SNI sebelum memerlukannya. Artinya, Anda tidak dapat memaksa pengguna menggunakan SNI HTTPS dan kemudian mundur jika mereka tidak mendukungnya, karena mereka akan menerima kesalahan seperti ini (dari Chrome di Windows XP) tanpa jalan untuk melanjutkan.

Jadi (sayangnya) pengguna harus benar-benar memulai koneksi HTTP yang tidak aman dan kemudian ditingkatkan hanya jika mereka mendukung SNI.

Anda dapat mendeteksi dukungan SNI melalui:

  1. Skrip jarak jauh
    Dari halaman HTTP biasa Anda, muat a <script>dari server HTTPS SNI tujuan Anda dan jika skrip dimuat dan berjalan dengan benar, Anda tahu browser mendukung SNI.

  2. Cross-Domain AJAX (CORS)
    Mirip dengan opsi 1, Anda dapat mencoba melakukan permintaan AJAX lintas-domain dari halaman HTTP ke HTTPS, tetapi perlu diketahui bahwa CORS hanya memiliki dukungan browser yang terbatas .

  3. Menghirup agen-pengguna
    Ini mungkin metode yang paling tidak dapat diandalkan, dan Anda harus memutuskan antara memiliki daftar hitam peramban (dan sistem operasi) yang diketahui tidak mendukungnya, atau daftar putih dari sistem yang dikenal yang melakukannya.

    Kita tahu bahwa semua versi IE, Chrome & Opera di Windows XP dan di bawahnya tidak mendukung SNI. Lihat CanIUse.com untuk daftar lengkap browser yang didukung .

Simon Timur
sumber