1

我正在寻找一种方法,将支持 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。
  • 这种方法有什么未知的问题吗?

学分:

4

1 回答 1

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 访问该页面,将被重定向到 http(检测和重定向支持 SNI 的浏览器的最有效代码是什么?):

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]
于 2015-01-12T05:52:32.887 回答