强制SSL和处理浏览器没有SNI支持

问题描述:

我正在寻找一种方式来重定向web浏览器与http支持SNI支持到https和webbrowsers从https到http没有SNI支持。第二种情况很重要,例如,如果用户获得通过邮件发送的https网址并用旧浏览器打开该网址。强制SSL和处理浏览器没有SNI支持

我想避免使用用户代理,因为我不想跟踪新的浏览器版本并更新配置文件,例如, .htaccess,相应地。

因此,我使用javascript来检测SNI支持并重定向webbrowser。以下代码检查连接是否受SSL保护。如果没有SSL保护,它会检查SNI支持和重定向是否支持SNI的浏览器:如果用户访问该网站的第一次,并使用SSL加密

<head> 
    <script type="text/javascript"> 
    if (window.location.protocol != "https:") { 
     var img=document.createElement('img'); 
     img.src='https://www.example.org/favicon.png'; 
     img.onload = function() { 
      window.location.href = "https:" + window.location.href.substring(window.location.protocol.length); 
     } 
     img.style.display='none'; 
     document.body.appendChild(img); 
    } 
    </script> 
    ... 
</head> 

,他被重定向到HTTP URL以运行JavaScript代码。否则,旧的浏览器会打开安全的网站并显示错误消息。

RewriteCond %{HTTPS} =on 
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example\.org [NC] 
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=302,L] 

更新1: 有重定向循环,因为JavaScript不提供一个引用。 该解决方案似乎避免循环:

<body> 
    <form style="display:none;" method="get" name="redirect"></form> 
    <script type="text/javascript"> 
     if (window.location.protocol != "https:") { 
     var img=document.createElement('img'); 
     img.src='https://www.example.org/favicon.png'; 
     img.onload = function() { 
      document.redirect.action = "https:" + window.location.href.substring(window.location.protocol.length); 
      document.forms['redirect'].submit(); 
     } 
     img.style.display='none'; 
     document.body.appendChild(img); 
     } 
    </script 
    ... 
</body> 

更新2: 我们希望避免重定向爬虫。

RewriteCond %{HTTPS} =on 
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?example\.org [NC] 
RewriteCond %{HTTP_USER_AGENT} !(googlebot|bingbot|baiduspider) [NC] 
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=302,L] 

更新3: 我们使用通过PHP(无重定向环路)更可靠的HTTPS检测。

<body> 
<?php if (empty($_SERVER["HTTPS"])) { ?> 
    <form style="display:none;" method="get" name="redirect"> 
     <input type="hidden" name="redirected" value="true" /> 
    </form> 
    <script type="text/javascript"> 
     var img=document.createElement('img'); 
     img.src='https://www.example.org/favicon.png'; 
     img.onload = function() { 
     var redirect_form = document.forms["redirect"]; 
     redirect_form.action = "https:" + window.location.href.substring(window.location.protocol.length); 
     redirect_form.submit(); 
     } 
     img.style.display='none'; 
     document.body.appendChild(img); 
    </script> 
<?php } ?> 
... 
</body> 

开放性问题:

  • 我怎样才能避免用户代理完全的使用情况如何?如果不可能,是否有任何重要的网络爬虫用户代理丢失?
  • 使用更新3中描述的方法,后退按钮无法正常工作。如果用户从http转发到https,然后单击后退按钮,他将重定向到http,然后再从http再次转到https。这个问题可以通过location.replace()来解决,但该方法不支持引用。
  • 在以下示例中,如何使用location.replace()和http://www.example.org作为引用?例如:google.de - >http://www.example.org - >https://www.example.org - >后退按钮点击 - >http://www.example.org(无重定向到google.de中!!!) - >https://www.example.org
  • 如果浏览器不支持javascript,它被强制使用HTTP。
  • 这种方法有什么未知的问题吗?

学分:

我决定放弃上述htaccess的规则,由于各种问题。用下面的代码,支持JavaScript和SNI网络浏览器重定向到SSL安全页面,而不在用户代理进行检查:

<body> 
<?php if (empty($_SERVER["HTTPS"])) { ?> 
    <form style="display:none;" method="get" name="redirect"></form> 
    <script type="text/javascript"> 
     var img=document.createElement('img'); 
     img.src='https://www.example.org/favicon.png'; 
     img.onload = function() { 
     var redirect_form = document.forms["redirect"]; 
     redirect_form.action = "https:" + window.location.href.substring(window.location.protocol.length); 
     redirect_form.submit(); 
     } 
     img.style.display='none'; 
     document.body.appendChild(img); 
    </script> 
<?php } ?> 
... 
</body> 

这些htaccess的规则,消除由以上表格创建尾随的问号:

RewriteCond %{HTTPS} =on 
RewriteRule ^(.*)$ - [env=proto:https] 
RewriteCond %{HTTPS} !=on 
RewriteRule ^(.*)$ - [env=proto:http] 

RewriteCond %{THE_REQUEST} \?\ HTTP [NC] 
RewriteRule .? %{ENV:proto}://%{HTTP_HOST}%{REQUEST_URI}? [R=301,L] 

不支持SNI旧的Web浏览器将被重定向到http如果他们访问,通过HTTPS页面(What is the most efficient code to detect and redirect SNI supported browsers?):

SetEnv SSL_TLS_SNI %{SSL:SSL_TLS_SNI} 

RewriteCond %{HTTPS} =on 
RewriteCond %{HTTP_USER_AGENT} MSIE\s6 [NC,OR] 
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s5 [NC,OR] 
RewriteCond %{HTTP_USER_AGENT} Android.*(Mobile)?\ [0-3] [NC,OR] 
RewriteCond %{HTTP_USER_AGENT} ^(.*.symbian.*) [NC,OR] 
RewriteCond %{HTTP_USER_AGENT} ^(.*.blackberry.*) [NC] 
RewriteCond %{SSL:SSL_TLS_SNI} ="" 
RewriteRule .* http://%{HTTP_HOST}%{REQUEST_URI} [R=307,L]