只有浏览器支持SNI才能redirect到SSL

我有Apache 2.2与mod_ssl和HTTPS在与VirtualHosting相同的IP /端口的一堆网站,所以客户端必须支持SNI连接到这些虚拟主机

我想用以下方式configuration我的服务器:

当用户键入www.dummysite.com并且他的浏览器支持 SNI(服务器名称指示)时,任何HTTP请求都被redirect到发送HSTS报头的地址https:// 。 但是,如果浏览器不支持 SNI,那么请求将由HTTP服务。

上述规则说明,对于那些仍然运行旧浏览器的用户来说实际上是一个后备规则,因为Mozilla和Chrome浏览器没有这个问题,只是为了避免这些用户离开网站。

我想在Apacheconfiguration级别redirect,也许在用户代理上使用filter。 我不想接触正在运行的应用程序,除非确保不存在直接的http://引用(否则它们意味着安全警告)

[编辑](编辑问题时,我忘问题):什么是启用SNI的用户代理redirect的列表?

由于SNI在SSL / TLS握手过程中发生,因此在客户端连接到HTTP时无法检测到浏览器支持。

所以,你是对的。 一个用户代理filter是唯一的方法来做到这一点。

最大的问题在于,您是否想要针对不知道SNI的浏览器或已知支持它的浏览器列入白名单。 晦涩的或新的设备无法使用该网站似乎是一个交易断路器,所以我会说白名单可能是更好的select。

在你的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] 

那里有很多浏览器。 我对expression式一直很宽松,没有涉及很多浏览器 – 这可能会变成相当噩梦来维护。

无论你select哪个选项..祝你好运!

我的解决办法是:

  # 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浏览器之前,它并不知道它要求哪个网站。 然后redirect到一个页面,告诉用户浏览器太旧(只要用户点击继续到网站)。

对于拥有新浏览器的用户

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

这排除了大多数旧的浏览器,包括Vista上的MSIE 5-8(9+仅支持Vista / 7,因此支持SNI)。 这不是100%(symbian被忽略等),但应为大多数工作。 less数人仍然可以select接受证书错误。

据我所知,这不是一个很好的方法 – 你可以使用mod_rewrite规则或类似的条件基于User-agent头,但它必须在一个非SSL的虚拟主机:如果浏览器支持SNI,它进入一个安全的( https:// )网站,它将得到老派阿帕克行为“这是我与该IP地址关联的第一个SSL证书 – 希望这是你想要的! “ – 如果这不是浏览器期望的证书,那么您将得到关于主机名不匹配的错误消息。

这基本上意味着用户必须打开一个非SSL插页式页面来redirect他们 – 可能会暴露他们在请求中发送的任何数据。 这可能会也可能不会成为一个交易断路器(如果你不支持SNI,你会说它会把它们发送到一个非SSL站点,所以我假设你不关心安全性。devise一个需要SSL作为encryption或authentication层的系统,虽然我会坚持一点,但…)

这些都不会阻止某人将书签放在安全网站上 – 而且,如果他们使用共享书签服务或将书签恢复到networking浏览器不支持SNI的机器,他们就会回到潜在的SSL错误案例。

我会试图解决这三个方面之一:

  1. 基于User-Agent头的RewriteRule
  2. 在非默认VHost的<SCRIPT>标记中加载https:// URI; 如果加载成功,这是一个JS重新加载HTTPS下的整个页面。
  3. 教我的访问者使用像HTTPS无处不在,如果这是他们的优先事项,强制HTTPS应该在需要的网页,并希望一切工作到最后。

其中,我个人喜欢#2最好,但涉及修改您的网站的代码。

只为需要它的人。

如果你有多台主机,并希望在VirtualHosting中启用SSL(并为每台主机购买了一个证书),请尝试使用新的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> 

正如我在这里发布的 ,你只能需要之前testingSNI支持。 也就是说,你不能强制用户进入SNI HTTPS,如果他们不支持,就会退后,因为他们会收到这样的错误(从Windows XP上的Chrome),无法继续。

所以(不幸的是)用户必须实际上开始一个不安全的HTTP连接,然后只有在他们支持SNI时才能升级。

您可以通过以下方式检测SNI支持:

  1. 远程脚本
    从普通的HTTP页面,从目标SNI HTTPS服务器加载<script> ,如果脚本加载并正确运行,则知道浏览器支持SNI。

  2. 跨域AJAX(CORS)
    与选项1类似,您可以尝试执行从HTTP页面到HTTPS的跨域AJAX请求,但请注意,CORS 仅支持有限的浏览器 。

  3. 嗅探用户代理
    这可能是最不可靠的方法,您需要决定是否有已知不支持的浏览器(和操作系统)的黑名单或已知系统的白名单。

    我们知道在Windows XP及以下版本的IE,Chrome和Opera的所有版本都不支持SNI。 有关支持的浏览器的完整列表,请参阅CanIUse.com 。