Chỉ chuyển hướng sang SSL nếu trình duyệt hỗ trợ SNI


20

Tôi có Apache 2.2 với mod_ssl và một loạt các trang web trong HTTPS trên cùng một IP / cổng với Virtualhosting, vì vậy máy khách phải hỗ trợ SNI để kết nối với các máy chủ ảo đó.

Tôi muốn cấu hình máy chủ của mình theo cách sau:

Khi người dùng nhập www.dummysite.com và trình duyệt của anh ta hỗ trợ SNI (Chỉ định tên máy chủ), mọi yêu cầu HTTP sẽ được chuyển hướng đến https://nơi gửi tiêu đề HSTS. Nhưng nếu trình duyệt không hỗ trợ SNI thì yêu cầu được cung cấp bởi HTTP.

Quy tắc trên, như đã nêu, thực sự là quy tắc dự phòng cho những người vẫn chạy các trình duyệt cũ, vì Mozilla và Chrome không gặp phải vấn đề này, chỉ để tránh những người dùng này rời khỏi trang web.

Tôi muốn thực hiện chuyển hướng này ở cấp cấu hình Apache, có lẽ với một bộ lọc trên tác nhân người dùng. Tôi không muốn chạm vào các ứng dụng đang chạy trừ việc đảm bảo rằng không có tài liệu tham khảo http: // trực tiếp nào xuất hiện (nếu không chúng có nghĩa là cảnh báo bảo mật)

[Chỉnh sửa] (trong khi chỉnh sửa các câu hỏi tôi quên các câu hỏi): danh sách các đại lý người dùng SNI-kích hoạt để chuyển hướng là gì?

Câu trả lời:


20

Vì SNI xảy ra trong quá trình bắt tay SSL / TLS, không thể phát hiện hỗ trợ trình duyệt khi máy khách kết nối với HTTP.

Vì vậy, bạn đã đúng; bộ lọc tác nhân người dùng là cách duy nhất để làm điều này.

Câu hỏi lớn là liệu bạn có muốn hành động trong danh sách đen đối với các trình duyệt mà bạn biết sẽ không nghe SNI hay danh sách trắng các trình duyệt được biết là hỗ trợ nó không. Các thiết bị mới tối nghĩa hoặc không thể sử dụng trang web có vẻ như là một công cụ thỏa thuận, vì vậy tôi nói rằng danh sách trắng có thể là lựa chọn tốt hơn.

Trong HTTP của bạn <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]

Đây cũng là tùy chọn danh sách đen - hãy nhớ rằng điều này có nguy cơ gửi một khách hàng không sử dụng SNI đến một trang web cần SNI, nhưng mặt khác, sẽ gửi cho người dùng một thứ gì đó mới như IE 10 ở bên phải địa điểm:

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

Có rất nhiều trình duyệt ngoài kia. Tôi đã khá lỏng lẻo với các biểu thức và không bao phủ nhiều trình duyệt - điều này có thể biến thành cơn ác mộng để duy trì.

Dù bạn chọn phương án nào .. chúc may mắn!


1
Tuyệt quá! Tôi đã thử nghiệm với Opera Mobile (tuân thủ SNI nhưng không có trong danh sách) và nó không chuyển hướng. Với Firefox của tôi, nó chuyển hướng!
usr-local-ΕΨΗΕΛΩΝ

6
Tôi đề nghị mô đun hóa giải pháp này bằng chỉ thị BrowserMatch từ mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html . Sử dụng BrowserMatch để đặt biến môi trường support_sni = y, sau đó viết RewriteCond% {ENV: hỗ trợ_sni} = y. Bằng cách đó, bạn có thể sử dụng lại logic phát hiện SNI cho bất kỳ RewriteRules nào khác mà bạn có thể có.
200_success

@ 200_success Ý kiến ​​hay!
Shane Madden

8

Giải pháp của tôi là thế này:

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

Nếu một trình duyệt cũ không có SNI cố gắng truy cập https://www.example.com/ * thì nó sẽ xuất hiện lỗi trên trình duyệt trước, điều này không thể tránh được cho đến khi apache trả lời trình duyệt không phải SNI thì không biết trang web nào nó đang yêu cầu. Sau đó, nó chuyển hướng đến một trang thông báo cho người dùng trình duyệt của họ quá cũ (miễn là người dùng nhấp vào trang web).

Và đối với người dùng có trình duyệt mới, tôi có

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

Điều đó loại trừ hầu hết các trình duyệt cũ, bao gồm một số như MSIE 5-8 trên Vista (9+ chỉ là Vista / 7 nên hỗ trợ SNI). Nó không phải là 100% (symbian bị bỏ qua, v.v.) nhưng sẽ hoạt động với đa số. Người thiểu số vẫn có thể chọn chấp nhận lỗi chứng chỉ.


3

Theo như tôi biết thì thực sự không phải là một cách hay để làm điều này - Bạn có thể sử dụng quy tắc mod_rewrite hoặc điều kiện tương tự dựa trên User-agenttiêu đề, nhưng nó sẽ phải nằm trên một vhost NON-SSL: Nếu trình duyệt không hỗ trợ SNI và nó đi đến một https://trang web ( ) an toàn để có được hành vi Apache cũ của trường học "Đây là chứng chỉ SSL đầu tiên tôi đã liên kết với địa chỉ IP đó - Hy vọng đó là điều bạn muốn!" - Nếu đó không phải là chứng chỉ mà trình duyệt mong đợi, bạn sẽ gặp phải thông báo lỗi về sự không khớp tên máy chủ.

Điều này về cơ bản có nghĩa là mọi người phải truy cập một trang xen kẽ không có SSL sẽ chuyển hướng họ - có thể làm lộ bất kỳ dữ liệu nào họ đang gửi trong yêu cầu của họ. Điều này có thể hoặc không phải là một công cụ thỏa thuận (bạn nói rằng dù sao bạn cũng sẽ gửi chúng đến một trang web không có SSL nếu chúng không hỗ trợ SNI, vì vậy tôi cho rằng bạn không quan tâm nhiều đến vấn đề bảo mật. thiết kế một hệ thống có nhu cầu SSL như một lớp mã hóa hoặc xác thực Tôi sẽ khăng khăng hơn một chút về nó mặc dù ...)

Không ai trong số đó ngăn ai đó đánh dấu trang web bảo mật - và nếu họ sử dụng dịch vụ đánh dấu chia sẻ hoặc khôi phục dấu trang của họ cho máy mà trình duyệt web không hỗ trợ SNI, họ sẽ quay lại trường hợp Lỗi tiềm năng cho SSL .


1

Tôi muốn giải quyết một trong ba cách sau:

  1. RewriteRuledựa trên User-Agentcác tiêu đề.
  2. Tải https: // URI trong <SCRIPT>thẻ trên Vhost không mặc định; nếu tải thành công, đó là một chút JS tải lại toàn bộ trang theo HTTPS.
  3. Dạy khách truy cập của tôi sử dụng một cái gì đó như HTTPS ở mọi nơi nếu đây là ưu tiên của họ, buộc HTTPS trên các trang cần được yêu cầu và hy vọng mọi thứ cuối cùng sẽ hoạt động.

Trong số này, cá nhân tôi thích thứ 2 nhất, nhưng điều đó liên quan đến việc sửa đổi mã trang web của bạn.


0

Chỉ cần cho bất cứ ai cần nó.

Nếu bạn có nhiều máy chủ và muốn tất cả chúng đều được bật SSL trong Virtualhosting (và bạn đã mua chứng chỉ cho từng máy chủ), hãy thử mới 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]

Sử dụng:

<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

Như tôi đã đăng ở đây , bạn chỉ có thể kiểm tra hỗ trợ SNI trước khi yêu cầu. Đó là, bạn không thể ép buộc người dùng vào SNI HTTPS và sau đó quay lại nếu họ không hỗ trợ, vì họ sẽ nhận được một lỗi như thế này (từ Chrome trên Windows XP) mà không có cách nào để tiếp tục.

Vì vậy, thật không may, người dùng phải thực sự bắt đầu qua kết nối HTTP không an toàn và sau đó chỉ được nâng cấp nếu họ hỗ trợ SNI.

Bạn có thể phát hiện hỗ trợ SNI thông qua:

  1. Tập lệnh từ xa
    Từ trang HTTP đơn giản của bạn, tải a <script>từ máy chủ SNI HTTPS đích của bạn và nếu tập lệnh tải và chạy chính xác, bạn biết trình duyệt hỗ trợ SNI.

  2. AJAX tên miền chéo (CORS)
    Tương tự như tùy chọn 1, bạn có thể thử thực hiện yêu cầu AJAX tên miền chéo từ trang HTTP đến HTTPS, nhưng lưu ý rằng CORS chỉ hỗ trợ trình duyệt hạn chế .

  3. Đánh hơi tác nhân người dùng
    Đây có lẽ là phương pháp ít tin cậy nhất và bạn sẽ cần phải quyết định giữa việc có một danh sách đen các trình duyệt (và hệ điều hành) được biết là không hỗ trợ nó hay danh sách trắng các hệ thống đã biết.

    Chúng tôi biết rằng tất cả các phiên bản IE, Chrome & Opera trên Windows XP trở xuống không hỗ trợ SNI. Xem CanIUse.com để biết danh sách đầy đủ các trình duyệt được hỗ trợ .

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.