利用Nginx的accesskey和secure_link模块实现防盗链

之前文章Nginx搭建flv mp4流媒体服务器中介绍了通过referer判断实现简单的防盗链,弊端是来源容易被伪造。今天介绍一下更高级的防盗链策略。

软件版本:
nginx-1.10.3
nginx-accesskey-2.0.3

增加编译参数 --with-http_secure_link_module --add-module=/root/nginx-accesskey-2.0.3 并重新编译 nginx

./configure --prefix=/usr/local/nginx --add-module=../nginx_mod_h264_streaming-2.2.7 --with-pcre=../pcre-8.41 --with-zlib=../zlib-1.2.11 --user=www --group=www --with-http_flv_module --with-http_stub_status_module --with-threads --with-http_ssl_module --with-http_secure_link_module --add-module=/root/nginx-accesskey-2.0.3 --with-openssl-opt=enable --with-http_v2_module --with-http_mp4_module --with-cc-opt='-O3'
make && make install

完整的配置文件示例:

user www www;

worker_processes auto;

error_log  /usr/local/nginx/logs/error.log  crit;

pid /usr/local/nginx/logs/nginx.pid;

events {
    use epoll;
    worker_connections 65535;
}

http {
    include mime.types;
    default_type application/octet-stream;
    
    server_names_hash_bucket_size 128;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 150m;
    tcp_nopush on;
    tcp_nodelay on;
    
    sendfile on;
    
    keepalive_timeout 65;
    limit_conn_zone $binary_remote_addr zone=perip:10m; #容器共使用10M的内存来应对IP传输开销
    
    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;
    gzip_proxied        expired no-cache no-store private auth;
    gzip_disable        "MSIE [1-6]\.";
    
    server {
        listen 80;
        listen 443 ssl; 
        server_name 2dan.cc; 
        root /home/html;
        limit_conn perip 3; #限制每个IP同一时间只能发起3个连接
        limit_rate_after 10m; #在视频文件下载10M以后开始限速
        limit_rate 100k; #速度限制为100K
        charset utf-8;
        
        ssl on;
        ssl_certificate      2dan.cc_bundle.crt;
        ssl_certificate_key  2dan.cc.key;
        ssl_session_timeout  5m;
        ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ALL:!ADH:!EXPORT56:-RC4+RSA:+HIGH:+MEDIUM:!EXP;
        ssl_prefer_server_ciphers on;
        error_page 497 https://$host$uri; #http重定向到https 

        location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        }
        
        location ~ \.(mp4|m3u8)$ {
                 mp4;
                 valid_referers none blocked *.2dan.cc; #防盗链授权
            if ($invalid_referer) {
                  return 403;
            }
            if (!-e $request_filename) {rewrite ^/(.*)/(.*)/(.*)/(.*) /$4?key=$1&st=$2&e=$3 last;}
            accesskey on;
            accesskey_hashmethod md5;
            accesskey_arg "key";
            accesskey_signature "mypass$REMOTE_ADDR";
            secure_link $arg_st,$arg_e;
            secure_link_md5 mypass$arg_e;
            if ( $secure_link = "" ) {
                return 402;
            }
            if ( $secure_link = "0" ) {
                return 405;
            }
        }
        access_log off;
    }
}

结合PHP实现自动跳转到真实链接地址

<?php
$key="mypass";
$ip=$_SERVER['REMOTE_ADDR'];
$newkey=md5($key.$ip);
$expire=time()+7200; // 过期时间为7200秒
$md5=base64_encode(md5($key.$expire,true));
$md5=strtr($md5,'+/','-_');
$md5=str_replace('=','',$md5);
$path=$_REQUEST["v"]; // ?v=path
$url = "$path?key=$newkey&st=$md5&e=$expire";
//$url="/".$newkey."/".$md5."/".$expire."/1.mp4";
header("Location:".$url);
//==防盗链=============================================================
$domain_list = array("2dan.cc","www.2dan.cc");//域名白名单。
$is_black_list = FALSE;
$allow_empty_referer = TRUE;

$referer = $_SERVER["HTTP_REFERER"];        
if($referer) {
        //解析来源地址
        $refererhost = parse_url($referer);
        //来源地址的主域名
        $host = strtolower($refererhost['host']);
        if($is_black_list) {
                //如果是黑名单
                if (in_array($host, $domain_list)) {
                          header('HTTP/1.1 404 Not Found');
                                                          exit;
                } else {
                        //succeed();
                }
        } else {
                //如果是白名单
                if($host == $_SERVER['HTTP_HOST'] || in_array($host, $domain_list)) {
                       // succeed();
                } else {
                            header('HTTP/1.1 404 Not Found');
                                                          exit;
                }
        }
} else {
        if ($allow_empty_referer) {
                //succeed();
        } else {
                            header('HTTP/1.1 404 Not Found');
                                                          exit;
        }
}
//防盗链========================
?>

生成的链接类似这样:

https://8.8.8.8/down.php?v=1.mp4
https://8.8.8.8/down.php?v=https://8.8.8.8/1.mp4

由于流媒体服务器上没有安装php环境,这里直接yum安装:

安装php-fpm并添加开机启动

yum --enablerepo=remi install php php-fpm php-gd php-mysql php-mbstring php-xml php-mcrypt
chkconfig --level 345 php-fpm on

启动php-fpm

/etc/init.d/php-fpm restart

配置 php-fpm 和 nginx,使它们一起工作

location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        }

重启nginx使配置生效

/usr/local/nginx/sbin/nginx -s reload

标签:Nginx, mp4, 流媒体, accesskey, secure_link, 模块, 防盗链

添加新评论