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

时间:2015-01-11 22:40:52

标签: ssl https sni

我一直在寻找一种方法,将支持SNI的网页浏览器从http重定向到https和webbrowsers,而不支持从https到http的SNI支持。第二种情况很重要,例如,如果用户通过邮件发送https url并使用旧浏览器打开它。

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

因此,我使用javascript来检测SNI支持并重定向webbrowser。以下代码检查连接是否受SSL保护。如果没有SSL保护,它会检查SNI支持并在支持SNI的情况下重定向浏览器:

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

如果用户第一次访问该网站并使用SSL加密,则会将其重定向到http网址以运行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()解决此问题,但该方法不支持referrer。
  • 在以下示例中,如何将location.replace()与http://www.example.org一起用作引荐来源?示例:google.de - &gt; http://www.example.org - &gt; https://www.example.org - &gt;后退按钮点击 - &gt; http://www.example.org(没有重定向到google.de !!!) - &gt; https://www.example.org
  • 如果浏览器不支持javascript,则强制使用http。
  • 这种方法有什么未知问题吗?

现金:

1 个答案:

答案 0 :(得分:1)

由于各种问题,我决定放弃htaccess规则。使用以下代码,支持Javascript和SNI的Web浏览器将被重定向到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]

如果通过https(What is the most efficient code to detect and redirect SNI supported browsers?)访问该页面,则不支持SNI的旧网络浏览器会重定向到http:

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]