背景
公司最近开发的项目涉及到相关文件服务器资源的权限问题,为了处理防盗链,研究了 一下如何利用nginx来进行防盗链处理;
目前了解到利用nginx实现防盗链有三种方式:
1:利用referer指令实现防盗链配置;(一般只适用与图片的防盗链处理,,因为referer信息可以伪造,不能达到完全防盗链的目的)
2:利用nginx-accesskey防盗链模块
3:还有一种就是今天实践尝试的:secure_link防盗链模块,nginx 自带的模块
环境
使用nginx配置一个静态页面web服务,在一个测试用的页面下然后利用反向代理,代理指定的访问的路径转发都其他python web服务(使用bottle运行的另一个web服务U)
相关的配置:
1:静态页面的web配置web.conf
server {
listen 80;
server_name 192.168.74.128;
root /data/app/html/;
location / {
index Index.html index.html;
#proxy_pass http://192.168.182.155:8089;
}
location ~* ^/(upload)/{
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.74.128:8089;
#alias /data/app/html2/static/$1; //文件可以放到别的目录
#error_page 404 =200 @backend; // 如果访问出现404转发到后台服务器
}
}
1:静态页面的index.html
protect
protect
2:python web 代理配置文件web_app.com(因为python web使用到了相关uwsgi启动相关服务,所以这些需要配置一下使用nginx进行访问uwsgi启动的python web)
server {
listen 8089;
server_name 192.168.74.128;
root /data/app/xianzhi/;
location / {
#这里配置了2个参数一个是st,一个是e
secure_link $arg_st,$arg_e;
#st的哈希格式为 secret+url+e,e为时间戳单位s,url为请求地址
secure_link_md5 xiaozhong.com$uri$arg_e;
#这里我们的st是我们按照secure_link_md5的方式计算的哈希,secure_link会比对它计算的哈希值是否与我们的st参数一致
if ($secure_link = "") {
#资源不存在或哈希比对失败
return 403;
}
if ($secure_link = "0") {
#时间戳过期
return 410;
}
if ($request_filename ~* ^.*?\.(mp4)$){
#直接下载防止打开文件 格式: (mp4|txt|jpg)
add_header Content-Disposition 'attachment;';
}
include uwsgi_params;
uwsgi_param UWSGI_PYHOME /data/app/xianzhi;
uwsgi_param UWSGI_CHDIR /data/app/xianzhi;
uwsgi_param UWSGI_SCRIPT app; # 对应main.py
uwsgi_pass 127.0.0.1:8086;
client_max_body_size 50m;
proxy_connect_timeout 1; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 120; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 120; #连接成功后,后端服务器响应时间(代理接收超时)
}
}
关键的配置:
其他示例:配合来路IP
Example:
location /s/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr secret";
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
...
}
The “/s/link?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647” link restricts access to “/s/link” for the client with the IP address 127.0.0.1. The link also has the limited lifetime until January 19, 2038 (GMT).
On UNIX, the md5 request argument value can be obtained as:
echo -n '2147483647/s/link127.0.0.1 secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
PS:上面的secure_link定义了控制权限的两个参数(分别是st, e)
其中e就是上述的过期时间,建议e = 当前时间 + 有效期限(5分钟)
3:然后使用python代码生成对应的 secure_link_md5信息,用于在nginx进行相关鉴权处理
生成相关URL地址示例:
#!/usr/bin/evn python
# coding=utf-8
# + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +
# ┏┓ ┏┓+ +
# ┏┛┻━━━┛┻┓ + +
# ┃ ┃
# ┃ ━ ┃ ++ + + +
# ████━████ ┃+
# ┃ ┃ +
# ┃ ┻ ┃
# ┃ ┃ + +
# ┗━┓ ┏━┛
# ┃ ┃
# ┃ ┃ + + + +
# ┃ ┃ Codes are far away from bugs with the animal protecting
# ┃ ┃ + 神兽保佑,代码无bug
# ┃ ┃
# ┃ ┃ +
# ┃ ┗━━━┓ + +
# ┃ ┣┓
# ┃ ┏┛
# ┗┓┓┏━┳┓┏┛ + + + +
# ┃┫┫ ┃┫┫
# ┗┻┛ ┗┻┛+ + + +
# + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +"""
"""
Author = zyx
@Create_Time: 2018/2/1 13:21
@version: v1.0.0
@Contact: [email protected]
@File: creat.py
@文件功能描述:
"""
import base64
import hashlib
import time
def md5(text, isBackByte=False):
"""md5加密函数"""
md5 = hashlib.md5()
if isinstance(text, bytes):
md5.update(text)
else:
md5.update(text.encode('utf-8'))
if isBackByte:
# 返回二进制的加密结果
return md5.digest()
# 返回十六进制的机密结果
return md5.hexdigest()
def base64_encode(text, isBytes=False):
"""进行base64编码处理"""
if isBytes:
return base64.b64encode(text)
return base64.b64encode(bytes(text, encoding="utf-8"))
def get_timestamp10():
"""获取当前时间长度为10位长度的时间戳"""
return int(time.time())
secret = 'xiaozhong.com'; # 密钥--对应#st的哈希格式为 secret+url+e,e为时间戳单位s,url为请求地址 secure_link_md5 xiaozhong.com$uri$arg_e;
path = '/upload/1.mp4' # 下载文件
# 下载到期时间,time是当前时间,300表示300秒,也就是说从现在到300秒之内文件不过期
expire = get_timestamp10() + 5;
res = md5(str(secret) + str(path) + str(expire), True)
print(res)
md5 = str(base64_encode(res, True))
print(md5)
print('expire', get_timestamp10())
print('md5', md5)
md5 = md5.replace('b\'', '').replace('\'', '').replace('+', '-').replace('/', '_').replace('=', '')
print('生成代相关认证签名的地址:','http://192.168.74.128/upload/1.mp4?' + 'st=' + str(md5) + '&e=' + str(expire))
4:测试访问对应的地址:
生成代相关认证签名的地址:
http://192.168.74.128/upload/1.mp4?st=x-N1ZsycbvlHvvDQNXMDLQ&e=1517758167
测试1:去除后面的参数,返回会返回403:
测试2:超时了时间戳有效期之后再访问具体,返回410
还可以添加其他的参数进行校验:
比如来源IP,UA信息等
注意事项PS:
部分的请求,如果直接不经过nginx访问的时候,可以直接进行处理,一个解决的方案就是设置防火墙,在linux中防火墙限制其端口,只能使用nginx进行访问,不能直接访问tomcat
加在自启动中
vim /etc/init.d/rc.local
设置如下
iptables -A INPUT -s 127.0.0.1 -p tcp -m tcp --dport 8080 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 8080 -j DROP
–A 参数就看成是添加一条规则
–p 指定是什么协议,我们常用的tcp 协议,当然也有udp,例如53端口的DNS
–dport 就是目标端口,当数据从外部进入服务器为目标端口
–sport 数据从服务器出去,则为数据源端口使用
–j 就是指定是 ACCEPT -接收 或者 DROP 不接收