0

通过伪造Referer来解决外链问题

发布于 2010年1月8日,归类为 PHP Web

什么是Referer?
Referer是HTTP Header的一个字段,当浏览器向服务器发送请求的时候一般会包含Referer信息,这一字段保存的是访客的来源URI。

以PHP为例,通过输出$_SERVER变量,你就可以看到HTTP_REFERER信息:

图1

图1

如今很多知名的网络相册(如网易相册、百度相册、51相册等等)都限制了外链,我不知道它们用什么方式实现,但是目前而言大多数防盗链的机制都是基于对Referer的判断来实现的。
比如说,我有一个网站,其中一个页面地址是 http://example.com/test.html,里面需要外链一张猫扑的图片,因此,image.html里面可以这么写:

1
<img src="http://upload3.mop.com/upload3/2009/12/18/08/1261139622733.jpg"/>

但是我们会发现这样外链的图片是无法显示出来的。原因在于,当我们访问http://example.com/test.html时,浏览器会向upload3.mop.com也就是猫扑的服务器发送一个请求,这一请求中包含的Referer信息应该就是这样:

http://example.com/test.html

这样,猫扑的服务器就可以判断出这是一个来自外部网站的请求,从而予以拒绝,这样我们就无法显示这张图片了。

那么,应该如何解决这一问题呢? 用火狐浏览器的可能知道,火狐有个插件叫做RefControl,可以用它来伪造Referer,从而正常显示图片。但是如果你是站长,你总不能要求你的访客都使用火狐浏览器对吧?即便你所有的访客都使用火狐浏览器,你也很难保证他们都安装了RefControl这个插件。
这样,我们只能从程序方面入手解决问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
ob_start();
$img=$_GET['url'];
 
$host=$path=str_replace('http://','',$img);
$host=explode('/',$host);
$host=$host[0];
$path=strstr($path,'/');
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if ($fp)
{
	@fputs($fp, "GET $path HTTP/1.1\r\n");
	@fputs($fp, "Host: $host\r\n");
	@fputs($fp, "Accept: */*\r\n");
	@fputs($fp, "Referer: http://$host/\r\n");
	@fputs($fp, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\n");
	@fputs($fp, "Connection: Close\r\n\r\n");
}
 
$Content = '';
while ($str = fread($fp, 4096))
	$Content .= $str;
@fclose($fp);
$pos=strpos($Content,"\r\n\r\n");
$head=substr($Content,0,$pos);
$text=substr($Content,$pos+4);
header($head);
echo $text;
?>

实际上这就是通过伪造Referer来实现我们想要的效果。
我们把这段程序保存为redirect.php,放到服务器上,例如http://example.com/redirect.php,那么,接下来我们只需要将原来的外链图片地址经由这段程序处理,就可以正常显示。

1
<img src="http://example.com/redirect.php?url=http://upload3.mop.com/upload3/2009/12/18/08/1261139622733.jpg"/>

效果如下:

图2

图2

由此可见,Referer信息不一定可靠,因为它是可以伪造出来的,通过这一手段来防盗链并不是一个完美的办法。
同时,我们也应该尽可能少的外链文件,毕竟大多数服务器都有带宽的限制和成本的考虑,限制外链对它们的生存也是很重要的。

如果您喜欢这篇文章,请将它分享到你所喜欢的社会性共享书签网站上:

发表评论