利用Nginx的accesskey和secure_link模块实现防盗链
之前文章Nginx搭建flv mp4流媒体服务器中介绍了通过referer判断实现简单的防盗链,弊端是来源容易被伪造。今天介绍一下更高级的防盗链策略。
软件版本:
nginx-1.22.1
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-tls1_3 enable-weak-ssl-ciphers' --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 http2 fastopen=3 reuseport;
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 TLSv1.3;
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
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