用户粘贴的图片是对方防盗链处理的图片,别人就无法看到图片了,体验很不好。
有问题就有解决办法,但需要预热一下:
1 别人是如何做图片防盗链的?
2 如何可以避免在防盗链范围?
了解或者解决以上两个问题你就可以出师了啦!
众所周知,图片防盗链是为了让自己的服务器提供给固定的某些域名下的网页显示自己的图片,主要为了解决带宽的占用问题。
阿权之前管理的图片类型的网站,居然可以让盗链的图片流量跑满了服务器带宽,所以盗链的问题很讨厌,一般网站都会处理此问题,一般采取的是检查图片请求的referer参数,这个不明白那这个课题还不适合你来读。
我们来看看凤凰网的图片防盗链,图片是很hot的美女哦,curl就可以测试:
[root@aslibra ~]# curl -I http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg
HTTP/1.1 200 OK
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:14:31 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Wed, 10 Jun 2009 11:16:05 GMT
Accept-Ranges: bytes
Content-Length: 37727
Expires: Wed, 23 Jun 2010 08:11:48 GMT
Cache-Control: max-age=31536000
X-Cache: HIT from cache26.ifeng.com
Age: 24507
X-Cache: HIT from CNC-BJBY-53-172.fastcdn.com
[root@aslibra ~]# curl -I http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg -H "referer:http://www.aslibra.com/"
HTTP/1.1 403 Forbidden
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:14:57 GMT
Content-Type: text/html
Connection: keep-alive
Content-Length: 1204
Expires: Fri, 26 Jun 2009 13:15:02 GMT
X-Squid-Error: ERR_ACCESS_DENIED 0
X-Cache: MISS from CNC-BJBY-53-172.fastcdn.com
[root@aslibra ~]# curl -I http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg -H "referer:http://img.ifeng.com/"
HTTP/1.1 200 OK
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:17:37 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Wed, 10 Jun 2009 11:16:05 GMT
Accept-Ranges: bytes
Content-Length: 37727
Expires: Wed, 23 Jun 2010 08:11:48 GMT
Cache-Control: max-age=31536000
X-Cache: HIT from cache26.ifeng.com
Age: 24691
X-Cache: HIT from CNC-BJBY-53-172.fastcdn.com
HTTP/1.1 200 OK
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:14:31 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Wed, 10 Jun 2009 11:16:05 GMT
Accept-Ranges: bytes
Content-Length: 37727
Expires: Wed, 23 Jun 2010 08:11:48 GMT
Cache-Control: max-age=31536000
X-Cache: HIT from cache26.ifeng.com
Age: 24507
X-Cache: HIT from CNC-BJBY-53-172.fastcdn.com
[root@aslibra ~]# curl -I http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg -H "referer:http://www.aslibra.com/"
HTTP/1.1 403 Forbidden
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:14:57 GMT
Content-Type: text/html
Connection: keep-alive
Content-Length: 1204
Expires: Fri, 26 Jun 2009 13:15:02 GMT
X-Squid-Error: ERR_ACCESS_DENIED 0
X-Cache: MISS from CNC-BJBY-53-172.fastcdn.com
[root@aslibra ~]# curl -I http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg -H "referer:http://img.ifeng.com/"
HTTP/1.1 200 OK
Server: DnionOS/1.0
Date: Fri, 26 Jun 2009 13:17:37 GMT
Content-Type: image/jpeg
Connection: keep-alive
Last-Modified: Wed, 10 Jun 2009 11:16:05 GMT
Accept-Ranges: bytes
Content-Length: 37727
Expires: Wed, 23 Jun 2010 08:11:48 GMT
Cache-Control: max-age=31536000
X-Cache: HIT from cache26.ifeng.com
Age: 24691
X-Cache: HIT from CNC-BJBY-53-172.fastcdn.com
第一个是没有来源标识的,一般为在窗口直接输入图片地址
第二个是模拟在网页里面的图片,网址假设为http://www.aslibra.com/
第三个是模拟在img.ifeng.com的网页打开的
第一个和第三个返回是200的状态码,图片正常,第二个则因为是非授权网页引用,返回了403禁止的消息。
也有可能是返回200的状态码的,比如百度hi的图片:
[root@aslibra ~]# curl -I http://hiphotos.baidu.com/yuanyingmanhua/pic/item/6e1da9d832163a3b33fa1c2b.jpg
HTTP/1.1 200 OK
...
Cache-Control: max-age=315360000
Expires: Sun, 08 May 2016 14:12:03 GMT
Last-Modified: Sat, 29 Apr 2006 07:04:00 GMT
Content-Length: 43171
...
[root@aslibra ~]# curl -I http://hiphotos.baidu.com/yuanyingmanhua/pic/item/6e1da9d832163a3b33fa1c2b.jpg -H "referer:http://www.aslibra.com/"
HTTP/1.1 200 OK
...
Cache-Control: no-cache
Content-Length: 1809
...
HTTP/1.1 200 OK
...
Cache-Control: max-age=315360000
Expires: Sun, 08 May 2016 14:12:03 GMT
Last-Modified: Sat, 29 Apr 2006 07:04:00 GMT
Content-Length: 43171
...
[root@aslibra ~]# curl -I http://hiphotos.baidu.com/yuanyingmanhua/pic/item/6e1da9d832163a3b33fa1c2b.jpg -H "referer:http://www.aslibra.com/"
HTTP/1.1 200 OK
...
Cache-Control: no-cache
Content-Length: 1809
...
当然,如果对方服务器是验证用户的信息的,那就没法解决了,我们能够解决的防盗链一般是根据来源防盗链的服务器。
注意了,破解对方的防盗链并非坏事,是为了提高用户体验,解决一般的用户的疑惑,他们根本不知道粘贴的图片为什么不正常,这你没必要跟他们聊一下图片防盗链吧?
你也许只要付出一台服务器就可以解决了:
1 首先你得把防盗链的域名的图片地址给替换为你的服务器域名,因为正常的访问你是控制不了referer信息的
2 交给代理服务器去掉或者修改referer信息,这个nginx很简便解决
3 再交给缓存服务器下载此图片,缓存此图片,这样对对方服务器没有什么影响,是好事来的
步骤1:替换图片地址
第一个就不用多说了,比如php就可以处理:
//example php code
$content = ereg_replace("http://($domain)/", "http://proxy.www.aslibra.com/m/\\1/", $content);
// from http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg
// to http://proxy.www.aslibra.com/m/img.ifeng.com/res/200906/0610-070615_1339_20.jpg
$content = ereg_replace("http://($domain)/", "http://proxy.www.aslibra.com/m/\\1/", $content);
// from http://img.ifeng.com/res/200906/0610-070615_1339_20.jpg
// to http://proxy.www.aslibra.com/m/img.ifeng.com/res/200906/0610-070615_1339_20.jpg
这样的简单处理可以保留所有的图片地址信息,而且可以自动还原原来的请求地址
步骤2 去掉或更改referer信息
这个有很多方法,比如配置proxy.www.aslibra.com/m交给php处理,php容易分析出地址,并且可以用socket或者调用curl等系统命令来下载图片,然后返回给用户。
这里用web服务器(nginx)解决这个问题,肯定比php来的简便和高效:
upstream squid {
server 127.0.0.1:3128;
}
server {
expires 240h;
server_name proxy.www.aslibra.com;
if ( $uri ~ ^/m/([^/]+)(.+)) {
set $new_host $1;
set $referer "";
#set $referer http://$1/; #you can set it like this
rewrite ^/m/([^/]+)(.+) $2 break;
}
location / {
proxy_set_header host $new_host;
proxy_set_header referer $referer;
proxy_pass http://squid;
}
}
server 127.0.0.1:3128;
}
server {
expires 240h;
server_name proxy.www.aslibra.com;
if ( $uri ~ ^/m/([^/]+)(.+)) {
set $new_host $1;
set $referer "";
#set $referer http://$1/; #you can set it like this
rewrite ^/m/([^/]+)(.+) $2 break;
}
location / {
proxy_set_header host $new_host;
proxy_set_header referer $referer;
proxy_pass http://squid;
}
}
简单来说就是rewrite回原先的地址,并且设置referer,交给squid的后端。
步骤3 交给代理服务器缓存
visible_hostname cache.aslibra.com
acl all src 0.0.0.0/0.0.0.0
http_access allow all
http_port 127.0.0.1:3128
httpd_accel_host virtual
httpd_accel_port 80
httpd_accel_uses_host_header on
httpd_accel_with_proxy off
cache_dir ufs /cache/proxy.www.aslibra.com 2000 16 256
cache_effective_user daemon
cache_access_log none
cache_store_log none
cache_log none
acl all src 0.0.0.0/0.0.0.0
http_access allow all
http_port 127.0.0.1:3128
httpd_accel_host virtual
httpd_accel_port 80
httpd_accel_uses_host_header on
httpd_accel_with_proxy off
cache_dir ufs /cache/proxy.www.aslibra.com 2000 16 256
cache_effective_user daemon
cache_access_log none
cache_store_log none
cache_log none
以上是squid的配置(2.5版本),基本不用配置什么参数,能代理缓存即可,有别的合适软件也许也可以做,但squid做这个实在是太合适了!你的不二之选!
实验效果很正常,返回的信息如下,访问两次有HIT说明就正常了:
(Status-Line) HTTP/1.1 200 OK
Cache-Control max-age=864000
Connection keep-alive
Content-Length 59969
Content-Type image/jpeg
Date Fri, 26 Jun 2009 13:42:32 GMT
Expires Mon, 06 Jul 2009 13:42:32 GMT
Last-Modified Mon, 18 Dec 2006 07:25:14 GMT
Server nginx/0.7.59
X-Cache HIT from cache.aslibra.com
Cache-Control max-age=864000
Connection keep-alive
Content-Length 59969
Content-Type image/jpeg
Date Fri, 26 Jun 2009 13:42:32 GMT
Expires Mon, 06 Jul 2009 13:42:32 GMT
Last-Modified Mon, 18 Dec 2006 07:25:14 GMT
Server nginx/0.7.59
X-Cache HIT from cache.aslibra.com
效果对比,前面会提示禁止引用,后面是解决后正常显示图片的效果!
很神奇吧~~ 这样就为用户体验提高了一个等级啦~
注意,以上方案域名为测试指定,访问并非正常,请自行修改相关内容进行试验,大家使用愉快!
本方案更新请关注:
http://www.aslibra.com/blog/post/crack_pic_referer_solution.php
本解决方案目前无法解决的类型:
1 不是判断referer信息来防盗链的,当然如果你知道,也许可以类似方式解决
2 不能解决redirect后的图片,也许可以使用nginx的内部redirect来处理,还没试验,这类情况还不多