标准参考
根据 HTTP1.1 规范中的描述,请求头中的 Referer 字段允许用户端为服务端指定得到的请求 URI 的资源地址 (URI),允许服务端生成资源的反向链接列表,同时也允许追踪维护过时的或者是拼写错误的链接。若一个请求 URI 获得自一个没有自身 URI 的源,则该请求 URI 的 Referer 字段不得被发送,如来自用户键盘的输入。
Referer = "Referer" ":" ( absoluteURI | relativeURI )
如:Referer: http://www.w3.org/hypertext/DataSources/Overview.html
关于 Referer 的更多信息,请参考 Hypertext Transfer Protocol -- HTTP/1.1 规范 14.36 Referer 中的内容。
问题描述
IE6 IE7 IE8 始终不在使用 META 元素控制跳转时附加 Referer 字段到请求头中。在普通页面中,当脚本调用 location 对象进行跳转时也不会附加 Referer 字段信息;
Firefox 始终不在使用 META 元素控制跳转时附加 Referer 字段到请求头中。
造成的影响
若服务端依靠请求头中的 Referer 字段信息进行某些操作,则在使用 META 元素进行页面跳转以及脚本 location 对象进行跳转时在某些浏览器中由于无 Referer 字段而产生差异。
受影响的浏览器
IE6 IE7 IE8 | |
---|---|
Firefox |
问题分析
创建一个 Web 服务器,如 Apache。在服务器上编写一段动态代码,用于输出接收到的请求头的 Referer 字段信息。如:refer.php
<?php echo '<style>* { font:12px "Trebuchet MS"; }</style>'; echo (isset($_SERVER['HTTP_REFERER'])) ? 'Referer: ' . $_SERVER['HTTP_REFERER'] : 'Referer: N/A'; ?>
本文中将测试 5 种常见的跳转方式,并分别在普通页面及 IFRAME 框架页内测试这些跳转方式下请求头 Referer 字段的发送情况。
5 种跳转方式代码:
anchor.html | <a href="refer.php">Anchor</a> |
---|---|
form_submit.html | <body>
<form action="refer.php"><input type="submit" /></form>
<script>
document.forms[0].submit();
</script>
</body> |
meta.html | <meta http-equiv="refresh" content="1;url=refer.php"> |
http302.php | <?php
header('Location: refer.php');
?> |
location.html | <script>location.href="refer.php";</script> |
测试页面:
index.html | <!DOCTYPE html> <html> <head> <base target="_blank" /> <style> * { margin:0; font:16px 'Trebuchet MS'; } </style> </head> <body> <a href="anchor.html">Anchor</a><br /> <a href="form_submit.html">Form submit</a><br /> <a href="meta.html">META</a><br /> <a href="302.php">HTTP 302</a><br /> <a href="location.html">location.href</a> </body> </html> |
---|---|
iframe.html | <!DOCTYPE html> <html> <head> <style> * { margin:0; font:16px 'Trebuchet MS'; } iframe { width:400px; height:40px; display:block; } </style> </head> <body> <h1>Anchor:</h1> <iframe id="anchor" name="anchor" scrolling="no" frameborder="0" src="anchor.html"></iframe> <h1>Form submit:</h1> <iframe id="form_submit" name="form_submit" scrolling="no" frameborder="0" src="form_submit.html"></iframe> <h1>META:</h1> <iframe id="meta" name="meta" scrolling="no" frameborder="0" src="meta.html"></iframe> <h1>HTTP 302:</h1> <iframe id="http302" name="http302" scrolling="no" frameborder="0" src="302.php"></iframe> <h1>location.href:</h1> <iframe id="loc" name="loc" scrolling="no" frameborder="0" src="location.html"></iframe> </body> </html> |
在各浏览器中分别打开上表的 "index.html"、"iframe.html",对于页面 "anchor.html" 需要用户手动点击超链接。
这段代码在不同的浏览器环境中的表现:
IE6 IE7 IE8 | Firefox | Chrome Safari Opera | ||
---|---|---|---|---|
index.html | 普通超链接 anchor.html | OK | OK | OK |
表单提交 form_submit.html | OK | OK | OK | |
META 跳转 meta.html | Fail | Fail | OK | |
HTTP 302 跳转 302.php | OK | OK | OK | |
脚本 location.href 跳转 location.php | Fail | OK | OK | |
iframe.html | 普通超链接 anchor.html | OK | OK | OK |
表单提交 form_submit.html | OK | OK | OK | |
META 跳转 meta.html | Fail | Fail | OK | |
HTTP 302 跳转 302.php | OK | OK | OK | |
脚本 location.href 跳转 location.php | OK | OK | OK |
可见,对于普通超链接、表单提交、302 跳转,各浏览器均会在请求头附加 Referer 字段信息,而对于 META 元素控制跳转及通过脚本使用 location 对象进行跳转时:
- 在 IE6 IE7 IE8 中,始终不在使用 META 元素控制跳转时附加 Referer 字段到请求头中。在普通页面中,当脚本调用 location 对象进行跳转时也不会附加 Referer 字段信息;
- 在 Firefox 中,始终不在使用 META 元素控制跳转时附加 Referer 字段到请求头中;
- 在 Chrome Safari Opera 中,则对于测试的 5 种方式下均会附加 Referer 字段信息。
解决方案
若服务端需要获得正确的 Referer 字段信息,则应采用各浏览器均可以附加 Referer 字段信息的方式进行跳转。如,普通超链接、表单提交、HTTP 302 跳转。