在折腾squid的rewrite.pl时,参考的是公司原有的一个防盗链脚本。如下:
#! /usr/bin/env perl
use strict;
use Digest::MD5 qw(md5_hex);
use POSIX qw(difftime mktime);
$| = 1;
my $errUrl = "http://www.test.com/no_such_url.html";
my $secret = "123456";
my $expired = 7200;
while () {
my ($uri, $client, $ident, $method) = split;
print "$errUrln" and next unless ($uri =~ m#^(http://w*.?test.com)/(d{4})(d{2})(d{2})(d{2})(d{2})/(w{32})(/.+.mp3)$#i);
my ($domain, $year, $mon, $mday, $hour, $min, $md5, $path) = ($1, $2, $3, $4, $5, $6, $7, $8);
print "$errUrl\n" and next if $year < 1990 or $mon == 0 or $mon > 12 or $mday == 0 or $mday > 31 or $hour > 23 or $min > 59;
print "$errUrl\n" and next if abs(difftime((int(time() / 100) * 100), mktime(00, $min, $hour, $mday, $mon - 1, $year - 1900))) > $expired;
$path =~ s#%(..)#pack("c", hex($1))#eg;
print "$errUrl\n" and next if $md5 ne md5_hex($secret . $year . $mon . $mday . $hour . $min . $path);
print $domain . $path, "\n";
}
今天在网上看到lighttpd相似的配置。lighttpd自带mod_secdownload模块实现这种防盗链方法。具体配置及php代码如下例(详见http://trac.lighttpd.net/trac/wiki/Docs%3AModSecDownload):
<?
$secret = "verysecret"; //加密字符串,必须跟lighttpd.conf里边保持一致
$uri_prefix = "/dl/"; //虚拟的路径,必须跟lighttpd.conf里边保持一致
# filename
$f = "/secret-file.txt"; //实际文件名,必须要加"/"斜杠
# current timestamp
$t = time();
$t_hex = sprintf("%08x", $t);
$m = md5($secret.$f.$t_hex);
# generate link
printf('%s', $uri_prefix, $m, $t_hex, $f, $f);
?>
lighttpd配置文件:
server.modules = ( …, “mod_secdownload”, … )
secdownload.secret = “verysecret”
secdownload.document-root = “/home/www/servers/download-area/”
secdownload.uri-prefix = “/dl/”
secdownload.timeout = 10
nginx也有类似功能,不过不是自带,secure_link_module模块,打补丁需要重编译:
wget http://www.sbear.cn/wp-content/uploads/2009/09/nginx-secure-link-ttl.patch cd nginx-0.7.62 patch -p1 < ../nginx-secure-link-ttl.patch ./configure –with-http_secure_link_module …… 具体配置及php例子如下(详见http://wiki.nginx.org/NginxHttpSecureLinkModule):
location /down/ {
secure_link_secret "sbear.cn"; //密钥
secure_link_ttl on;
root /data/test/down;
if ($secure_link = "") {
return 403;
}
rewrite ^ /$secure_link break;
}
<?php
define(URL_TIMEOUT, 3600); //这里设置过期时间单位是秒
$prefix = "<a href="http://www.sbear.cn/down";">http://www.sbear.cn/down";</a>
$protected_resource = "test.exe";
$secret = "sbear.cn"; //密钥
$time = pack('N', time() + URL_TIMEOUT);
$timeout = bin2hex($time);
$hashmac = md5( $protected_resource . $time . $secret );
$url = $prefix . "/" . $hashmac . $timeout . "/" . $protected_resource;
echo "down";
echo time();
?>
那不打补丁,有什么防盗链的办法么?当然有。nginx和lighttpd都支持最简单的referer判断。
nginx有ngx_http_referer_module模块,和apache、squid一样可以rewrite,配置如下:
location ~* .(gif|jpg|png)$ {
valid_referers none blocked www.test.com baidu.com;
if ($invalid_referer) {
rewrite ^/ http://www.test.com/error.html;
}
}
lighttpd配置如下:
$HTTP[“referer”] !~ “^(http://..(test.com|baidu.cn))” { $HTTP[“url”] =~ “.(jpg|jpeg|png|gif|rar|zip|mp3|swf|flv|wmv|rm|avi)$” { url.redirect = (“.“ => http://www.test.com/”) } } 不过还是那句话,这个功能破解起来确实太容易,呵呵~
除了上面说的NginxHttpSecureLinkModule,还有另一个模块ngx_http_accesskey_module,其工作原理是根据client的IP,加上配置定义的key,生成32位MD5值,然后进行匹配。详见http://wiki.codemongers.com/NginxHttpAccessKeyModule,不过我这居然打不开……只好详见网友博客了:
wget http://wiki.nginx.org/File:Nginx-accesskey-2.0.3.tar.gz
tar zxvf Nginx-accesskey-2.0.3.tar.gz
sed -i ‘s/$HTTP_ACCESSKEY_MODULE/ngx_http_accesskey_module/g nginx-accesskey/config
./configure –add-module=/path/to/nginx-accesskey
#配置文件
location /download {
accesskey on;
accesskey_hashmethod md5;
accesskey_arg “key”;
accesskey_signature “mypass$remote_addr”;
}
//php测试页面,$output_add_key正常,$output_org_url返回403//
<?
$ipkey= md5(“mypass”.$_SERVER[‘REMOTE_ADDR’]);
$output_add_key=”http://www.example.cn/download/G3200507120520LM.rar?key=”.$ipkey.”>download_add_key
”;
$output_org_url=”<a href=http://www.example.cn/download/G3200507120520LM.rar>download_org_path
”;
echo $output_add_key;
echo $output_org_url;
?>
而另一个博客这么说:
wget http://www.ieesee.net:8080/~uingei/nginx-accesskey-2.0.3.diff.bz2
cd nginx-0.7.14
bzcat ../nginx-accesskey-2.0.3.diff.bz2 | patch -p1
./configure –with-http_accesskey_module …
根据我的观察,这个应该是最初的办法。另,该博客说sec_link是nginx0.7.18后加的官方模块。