【问题标题】:Force SSL and handle browsers without SNI support强制 SSL 并处理不支持 SNI 的浏览器
【发布时间】:2015-01-11 22:40:51
【问题描述】:

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

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

因此,我使用 javascript 来检测 SNI 支持并重定向网络浏览器。以下代码检查连接是否受 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 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() 解决,但是这个方法不支持referrer。
  • 在以下示例中,如何使用 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。
  • 这种方法是否存在任何未知问题?

致谢:

【问题讨论】:

    标签: ssl https sni


    【解决方案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]
    

    不支持 SNI 的旧 Web 浏览器如果通过 https (What is the most efficient code to detect and redirect SNI supported browsers?) 访问页面,将被重定向到 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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 2011-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      相关资源
      最近更新 更多