Перенаправляємо на 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: // посилань немає (інакше вони мають на увазі попередження про безпеку)

[Edit] (при редагуванні питання , який я забув на питання): що список 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
Я пропоную модулювати це рішення за допомогою директиви BrowserMatch від mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html . Використовуйте BrowserMatch, щоб встановити змінну середовища підтримка_sni = y, а потім напишіть RewriteCond% {ENV: supports_sni} = y. Таким чином, ви можете повторно використовувати логіку виявлення SNI для будь-яких інших RewriteRules, які у вас можуть бути.
200_успіх

@ 200_success Гарна ідея!
Шейн Медден

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заголовку, але це повинно бути на vonst NON-SSL: Якщо браузер не робить підтримка SNI, і він переходить на захищений ( https://) сайт, він отримає стару школу Apache поведінки "Ось перший сертифікат SSL, який я пов’язав з цією IP-адресою. Сподіваюся, це те, що ви хотіли!" - Якщо це не сертифікат, браузер очікував, що ви закінчите повідомлення про помилку щодо невідповідностей імені хоста.

Це в основному означає, що люди повинні потрапляти на проміжну сторінку без SSL, яка буде перенаправляти їх - можливо, відкривати будь-які дані, які вони надсилають у своєму запиті. Це може бути, а може і не бути зловмисником угод (ви кажете, що все одно будете відправляти їх на не-SSL-сайт, якщо вони не підтримують SNI, тому я припускаю, що ви не так сильно переймаєтесь безпекою. Якби я був проектування системи, яка мала потребу в SSL як шарі шифрування або автентифікації, хоч би я трохи наполегливіший щодо цього ...)

Ніщо з цього не зупиняє когось із закладки захищеного сайту - і якщо вони використовують спільну службу закладок або відновлять свої закладки на машині, де веб-браузер не підтримує SNI, вони повернулися у випадку Potential-for-SSL-Errors. .


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 завантажте a <script>з вашого призначення на сервер SNI HTTPS, і якщо сценарій завантажується та працює правильно, ви знаєте, що браузер підтримує SNI.

  2. Міждоменний AJAX (CORS)
    Подібно до варіанту 1, ви можете спробувати виконати запит AJAX між доменами зі сторінки HTTP на HTTPS, але пам’ятайте, що CORS має лише обмежену підтримку браузера .

  3. Відшукуйте користувальницький агент
    Це, мабуть, найменш надійний метод, і вам потрібно буде вирішити між наявністю чорного списку веб-переглядачів (та операційних систем), які не підтримують його, або списком відомих систем, які це роблять.

    Ми знаємо, що всі версії IE, Chrome і Opera для Windows XP і нижче не підтримують SNI. Див CanIUse.com для повного списку підтримуваних браузерів .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.