最佳实践11:优化缓存防盗链
盗链是指本网站的资源被非授权的第三方网站直接在页面中进行引用。对于被盗链的网站来说,盗链现象既浪费了大量的带宽又失去了对于版权文件的控制,因此需要在缓存节点上对URL进行校验,设置防盗链。防盗链的几个基本方法如下。
·使用HTTP Referer。HTTP Referer是HTTP请求的一个头部,用于标明被请求的资源是在哪个页面中进行调用的。对静态图片资源文件,使用HTTP Referer设置防盗链即可。
·使用生成动态链接的方法。这个方法的本质是首先在页面上产生资源URL的时候,使用动态编程语言,生成类似如下结构http://music1.woyo.com/music1-abcdefghijk.mp3?key=xxxxyyyyzzzzaaaadddd。在缓存节点上收到用户的请求时,对该URL的key进行验证。该方法一般用于视频、音频等比较大的文件的防盗链检查。
Key的组成
其中key=20080722101000A-MD5-KEY表示一个加密串。加密串包括以下两个部分。
·20080722101000:表示时间戳,即年月日时分秒。
·A-MD5-KEY:一个MD5串,其计算方式如下为A-MD5-KEY=md5(base_url+datetime+password)。其中,base_url即请求中的http://music1.woyo.com/music1-abcdefghijk.mp3;datetime为请求中的时间戳20080722101000;password是源站和CDN约定的一个密码。
校验过程
具体的校验过程如下:
1)检查防盗链的串(即key)是否存在,如果不存在,则返回校验失败。
2)从防盗链串中取出日期时间,与当前时间比较,如果超出有效期范围(例如,如果与当前时间相减,大于±2小时),则返回校验失败。
3)生成MD5的值,与请求中的A-MD5-KEY相比较,如果不等,则返回校验失败。
4)如果上述步骤都通过,则返回校验成功。
5)如果校验成功,则CDN缓存服务器向用户返回正常的响应。
6)如果校验失败,则向把请求重定向到广告音频。
实施过程
在Squid配置文件中/usr/local/squid/etc/squid.conf增加如下配置:
redirect_program /usr/local/squid/etc/checkkey.pl redirect_children 20
重定向器
安装Perl的MD5模块:
cd /root wget http://www.kamnet.cn/srv/Digest-MD5-2.36.tar.gz wget http://www.kamnet.cn/srv/Digest-Perl-MD5-1.8.tar.gz tar xvfz Digest-MD5-2.36.tar.gz cd Digest-MD5-2.36 perl Makefile.PL make make install cd .. tar xvfz Digest-Perl-MD5-1.8.tar.gz cd Digest-Perl-MD5-1.8 perl Makefile.PL make make install
源码(checkkey.pl):
#!/usr/bin/perl -wl use Digest::Perl::MD5 'md5_hex'; use POSIX qw(strftime); $|=1; my $password = 'IblessWoyo'; my $errurl = 'http://err.woyo.com/woyo.mp3'; my $result = 'http://err.woyo.com/woyo.wma'; while (<>) { ($uri,$client,$ident,$method) = ( ); ($uri,$client,$ident,$method) = split; #解析Squid传入的参数 my $time_from = strftime "%Y%m%d%H%M%S", localtime(time - 1*3600); my $time_to = strftime "%Y%m%d%H%M%S", localtime(time + 1*3600); next unless ($uri =~m/^http:\/\/(.+?)\/(.*)\?key=([0-9]{14})(.+)$/); if (($4 eq md5_hex("/".$2.$3.$password)) && ($3 > $time_from) && ($3 < $time_to)) { #检查md5和URL中包含的时间 $result = "http:\/\/$1:81\/$2"; } else { $result = $errurl; } } continue { print $result; #通知Squid防盗链检查结果 }