Nginx的防盗链
一般的防盗链如下:
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.ccvita.com www.phpq.net;
if ($invalid_referer) {
rewrite ^/ http://www.ccvita.com/403.html;
#return 404;
}
}
第一行:gif|jpg|png|swf|flv
表示对gif、jpg、png、swf、flv后缀的文件实行防盗链
第二行:www.ccvita.com www.phpq.net
表示对www.ccvita.com www.phpq.NET这2个来路进行判断
if{}里面内容的意思是,如果来路不是指定来路就跳转到错误页面,当然直接返回404也是可以的。

NginxHttpAccessKeyModule实现防盗链
如果不怕麻烦,有条件实现的话,推荐使用NginxHttpAccessKeyModule这个东西。

他的运行方式是:如我的download 目录下有一个 file.zip 的文件。对应的URI 是http://www.ccvita.com/download/file.zip

使用ngx_http_accesskey_module 模块后http://www.ccvita.com/download/file.zip?key=09093abeac094. 只有给定的key值正确了,才能够下载download目录下的file.zip。而且 key 值是根据用户的IP有关的,这样就可以避免被盗链了。



安装Nginx和nginx-http-access模块

#tar zxvf nginx-0.7.61.tar.gz
#cd nginx-0.7.61/
#tar xvfz nginx-accesskey-2.0.3.tar.gz
#cd nginx-accesskey-2.0.3 
#vi config
#把HTTP_MODULES="$HTTP_MODULES $HTTP_ACCESSKEY_MODULE" 修改成HTTP_MODULES="$HTTP_MODULES ngx_http_accesskey_module" (这是此模块的一个bug)
#./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-module=/root/nginx-accesskey-2.0.3

#make && make install
#cd ../

修改Nginx日志目录权限
#chmod +w /logs
#chown -R www:www /logs

创建Nginx配置文件
在/usr/local/nginx/conf/目录中创建nginx.conf文件:

#rm -f /usr/local/nginx/conf/nginx.conf
#vi    /usr/local/nginx/conf/nginx.conf


输入以下内容:

user  www www;
worker_processes 8;
error_log  /usr/local/nginx/logs/nginx_error.log  crit;
pid        /usr/local/nginx/nginx.pid;
#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 51200;

events
{
  use epoll;
  worker_connections 51200;
}

http
{
  include       mime.types;
  default_type  application/octet-stream;

  #charset  gb2312;

  server_names_hash_bucket_size 128;
  client_header_buffer_size 32k;
  large_client_header_buffers 4 32k;
  client_max_body_size 8m;

  sendfile on;
  tcp_nopush     on;

  keepalive_timeout 60;

  tcp_nodelay on;

  fastcgi_connect_timeout 300;
  fastcgi_send_timeout 300;
  fastcgi_read_timeout 300;
  fastcgi_buffer_size 64k;
  fastcgi_buffers 4 64k;
  fastcgi_busy_buffers_size 128k;
  fastcgi_temp_file_write_size 128k;

  gzip on;
  gzip_min_length  1k;
  gzip_buffers     4 16k;
  gzip_http_version 1.0;
  gzip_comp_level 2;
  gzip_types       text/plain application/x-javascript text/css application/xml;
  gzip_vary on;

  autoindex on;
  autoindex_exact_size off;
  autoindex_localtime on;

  #limit_zone  crawler  $binary_remote_addr  10m;

  server
  {
    listen       80;
    server_name  www.91vmall.com;
    index index.html index.htm index.php;
    if (-d $request_filename)
      {
            rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
      }
    root  /www/htdocs/vmall_shop;

    #limit_conn   crawler  20;

    location ~ .*\.(php|php5)?$
    {
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
      expires      30d;
    }

    location ~ .*\.(js|css)?$
    {
      expires      1h;
    }

    location /shop
    {
   accesskey             on;
   accesskey_hashmethod   md5;
   accesskey_arg         "key";
   accesskey_signature   "91vmall$remote_addr";
   error_page 403 = http://192.168.1.24/error.php;
    }
    log_format  access  '$remote_addr - $remote_user [$time_local] "$request" '
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for';
    access_log  /logs/access.log  access;
      }

  server
  {
    listen       80;
    server_name  mantis.91vmall.com;
    index index.html index.htm index.php;
    if (-d $request_filename)
      {
            rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
      }
    root  /www/htdocs/mantis;

    location ~ .*\.(php|php5)?$
    {
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }

    log_format  wwwlogs  '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" $http_x_forwarded_for';
    access_log  /logs/wwwlogs.log  wwwlogs;
  }

  server
  {
    listen  80;
    server_name  status.91vmall.com;

    location / {
    stub_status on;
    access_log   off;
    }
  }
}


在/usr/local/nginx/conf/目录中创建fcgi.conf文件:

#vi /usr/local/nginx/conf/fcgi.conf
输入以下内容:
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

启动Nginx

#ulimit -SHn 51200
#/usr/local/nginx/sbin/nginx


配置开机自动启动Nginx + PHP

#vi /etc/rc.local
在末尾增加以下内容:
#php nginx start
ulimit -SHn 51200
/usr/local/php/sbin/php-fpm start
/usr/local/nginx/sbin/nginx


优化nginx配置:(此步骤已经做好,以下做法仅作参考资料存在)
#vi /usr/local/nginx/conf/nginx.conf
nginx默认是不允许列出整个目录的,如需此功能在location server 或 http段中加入
autoindex on;
另外两个参数最好也加上去
autoindex_exact_size off;  
默认为on,显示出文件的确切大小,单位是bytes。
改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
autoindex_localtime on;
默认为off,显示的文件时间为GMT时间。
改为on后,显示的文件时间为文件的服务器时间。

在以下位置处加入代码解决nginx无法访问二级目录的问题
server
  {
    listen       80;
    server_name  91vmall;
    index index.html index.htm index.php;
加入的正则开始/
    if (-d $request_filename)
      {
            rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
      }
加入的正则结束
    root  /www/htdocs/test;
    #limit_conn   crawler  20;
    location ~ .*\.(php|php5)?$
    {
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
      expires      30d;
    }
    location ~ .*\.(js|css)?$
    {
      expires      1h;
    }
    log_format  access  '$remote_addr - $remote_user [$time_local] "$request" '
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for';
    access_log  /www/logs/access.log  access;
  }

nginx下载认证的配置:

开发者:  OWOX project   http://www.owoxengine.com/
配置方法
 
需要在nginx的配置文件里面添加:

location /data/shop
{
   accesskey               on;
   accesskey_hashmethod   md5;
   accesskey_arg         "key";
   accesskey_signature   "91vmall$remote_addr";
   error_page 403 = http://www.91vmall.com/?tips=download_not_permit;
}

语法解释:
accesskey [on|off]
默认是off。
用 on 开启这个功能。
accesskey_arg "key"
默认是 key,就是用于http://example.com/download/file.zip?key=09093abeac094 里面的 key。
如果使用 accesskey_arg "string"
要下载就应该是 http://example.com/download/file.zip?string=09093abeac094
 
accesskey_hashmethod [md5|sha1]
默认是 md5.
这里是选择哈希的类型,随便用哪个都可以,不过在生成下载URL的时候需要使用相应的哈希方法
 
accesskey_signature "string"
默认是accesskey_signature "$remote_addr"
这里是被签名(哈希)的字符串。
$remote_addr 表示用户的 ip。
为了很好的防盗链,这里应该给用户ip加上噪声。让别人无法猜到。
比如accesskey_signature " myPassWord $remote_addr"

生成下载URI 的方法:
Nginx参考配置:
location /data/shop
{
   accesskey               on;
   accesskey_hashmethod   md5;
   accesskey_arg         "key";
   accesskey_signature   "91vmall$remote_addr";
   error_page 403 = http://www.91vmall.com/?tips=download_not_permit;
}

PHP参考代码:
function get_download_url($url)
{
   $secret = "91vmall";
   //注意,需要考虑部署在代理后端的情况,获取的IP如果和下载服务器获取的不一致,那会导致地址失败
   $m = md5($secret.$_SERVER['REMOTE_ADDR']);
   return $url."?key=".$m;
}

按照以上的设置,shop文件夹下所有的压缩包如果用地址直接引用,
比如http://www.91vmall.com/shop/test.rar,都会提示403错误,
无法访问到资源,这也就是我们说的防盗链功能已经生效。
那么要如何才能让我们的目标用户下载这些文件呢?方法就是我们要给用户一个正确的链接,
形如http://www.91vmall.com/shop ... 3b5423523952352bg2g
这个key后面的参数是根据前面设定的accesskey_hashmethod和accesskey_signature确定的,
比如我们前面的设定就是对password$remote_addr($remote_addr代表客户端传递过来的IP)的值进行MD5加密运算得到的结果。
我们要把带有key值的地址重新定向给目标用户,这样我们的目标用户才能下载到资源,没有key或者key值错误,
都将被认为是盗链,而无法下载。

下面我们用PHP脚本的header重定向函数举例说明:
//其他代码省略

//header函数实现重定向
header("location:http://www.91vmall.com/shop/test.rar?key=".md5("password".$_SERVER['REMOTE_ADDR']));

这样用户就能顺利访问到含有正确key值的资源了。
最后提一句,要实现真正的深度防盗链,需要有冗余备份防盗链措施辅助,比如你可以即使用传统的判断referer的防盗链,
再结合accesskey模块,那么大约能够保证万无一失了.

key加密方法:
给这个字符串md5加密"123443555$remote_addr"    //密钥字符串,变量$remote_addr是客户端ip地址
生成的加密串是32位小写的:7f938c21e8669463a881d4b6509b8c04

关于资源加密和防盗链:
正常的资源真实地址http://www.xxx.com/x/x.rar  这个直接下是非法的会被拒绝
用户要在网站点击下载某个文件的时候程序自动生成一个key,然后给他一个下载链接,他用这个连接就能合法下载了
http://www.xxx.com/x/x.rar?key=7f938c21e8669463a881d4b6509b8c04
每个客户每次下载的时候都要生成一次这个key 

当他下完把这个链接复制给别人或者发布到其它网站的时候 因为ip不同别人就下不了