我一直在寻找一种方法,将支持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>
未解决的问题:
现金:
答案 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]