Python的Flask框架及Nginx实现静态文件访问限制功能


Posted in Python onJune 27, 2016

Nginx配置

Ngnix,一个高性能的web服务器,毫无疑问它是当下的宠儿。卓越的性能,灵活可扩展,在服务器领域里攻城拔寨,征战天下。

静态文件对于大多数website是不可或缺的一部分。使用Nginx来处理静态文件也是常见的方式。然而,一些静态文件,我们并不像任何情况下都公开给任何用户。例如一些提供给用户下载的文件,一些用户上传的涉及用户隐私的图片等。我们我希望用户登录的情况下可以访问,未登录的用户则不可见。

粗略的处理,在后端程序可以做过滤,渲染页面的时候,在视图逻辑里面验证用户登录,然后返回对应的页面。例如下面的flask代码(伪代码)

@app.router('/user/idcard'):
def user_idcard_page():
 if user is login:
  return '<img src="/upload/user/xxx.png'>"
 else:
  reutrn '<p>Pemission Denied<p>', 403

可是这样的处理,还有一个问题,静态文件是交给 nginx 处理的,如果hacker找到了文件的绝对地址,直接访问 http://www.example.com/upload/user/xxx.png也是可以的。恰巧这些文件又涉及用户隐私,比如用户上传的身份证照片。那么码农可不希望第二天媒体报道,知名网站XXX存在漏洞,Hacker获取了用户身份证等信息。

为了做这样的限制,可以借助 Nginx 的一个小功能----XSendfile。 其原理也比较简单,大概就是使用了请求重定向。

我们知道,如果用Nginx做服务器前端的反向代理,一个请求进来,nginx先补捉到,然后再根据规则转发给后端的程序处理,或者直接处理返回。前者处理一些动态逻辑,后者多是处理静态文件。因此上面那个例子中,直接访问静态文件的绝对地址,Nginx就直接返回了,并没有调用后端的 user_idcard_page做逻辑限制。

为了解决这个问题,nginx提供的 XSendfile功能,简而言之就是用 internal 指令。该指令表示只接受内部的请求,即后端转发过来的请求。后端的视图逻辑中,需要明确的写入X-Accel-Redirect这个headers信息。

伪代码如下:

location /upload/(.*) {
  alias /vagrant/;
  internal;
}

@app.router('upload/<filename>')
@login_required
def upload_file(filename):
 response = make_response()
 response['Content-Type'] = 'application/png'
 response['X-Accel-Redirect'] = '/vagrant/upload/%s' % filename
 return response

经过这样的处理,就能将静态资源进行重定向。这样的用法还是比较常见的,很多下载服务器可以通过这样的手段针对用户的权限做下载处理。

Flask

Flask是我喜欢的web框架,Flask甚至实现了一个 sendfile的方法,比上面的做法还简单。我用vagrant作了一个虚拟机,用Flask实现了上面的需求,具体代码如下:

项目结构

project struct

project
 app.py
 templates
 static
 0.jpeg
 upload
 0.jpeg

nginx的配置 nginx conf

web.conf

server {
  listen 80 default_server;

  # server_name localhost;
  server_name 192.168.33.10;
  location / {
    proxy_pass http://127.0.0.1:8888;
    proxy_redirect off;
    proxy_set_header Host $host:8888;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  # 正常的静态文件
  location /static/(.*) {
    root /vagrant/;

  }
  # 用户上传的文件,需要做权限限制
  location /upload/(.*) {
    alias /vagrant/;
    internal;    # 只接受内部请求的指令
  }
}

Flask 代码

app.py

from functools import wraps
from flask import Flask, render_template, redirect, url_for, session, send_file

app = Flask(__name__)

app.config['SECRET_KEY'] = 'you never guess'

def login_required(f):
 @wraps(f)
 def decorated_function(*args, **kwargs):
  if not session.get('login'):
   return redirect(url_for('login', next=request.url))
  return f(*args, **kwargs)
 return decorated_function

@app.route('/')
def index():
 return 'index'


@app.route('/user')
@login_required
def user():

 return render_template('upload.html')

# 用户上传的文件视图处理,在此处返回请求给nginx
@app.route('/upload/<filename>')
@login_required
def upload(filename):

 return send_file('upload/{}'.format(filename))


@app.route('/login')
def login():
 session['login'] = True
 return 'log in'

@app.route('/logout')
def logout():
 session['login'] = False
 return 'log out'


if __name__ == '__main__':
 app.run(debug=True)

简单部署

gunicorn -w4 -b0.0.0.0:8888 app:app --access-logfile access.log --error-logfile error.log
Python 相关文章推荐
python 正则式 概述及常用字符
May 07 Python
Python中分数的相关使用教程
Mar 30 Python
python抓取百度首页的方法
May 19 Python
浅谈python中截取字符函数strip,lstrip,rstrip
Jul 17 Python
Python 如何访问外围作用域中的变量
Sep 11 Python
Python实现发送QQ邮件的封装
Jul 14 Python
Windows下将Python文件打包成.EXE可执行文件的方法
Aug 03 Python
解决python xlrd无法读取excel文件的问题
Dec 25 Python
对python中大文件的导入与导出方法详解
Dec 28 Python
pytorch中tensor张量数据类型的转化方式
Dec 31 Python
tensorflow 分类损失函数使用小记
Feb 18 Python
Python爬虫后获取重定向url的两种方法
Jan 19 Python
总结网络IO模型与select模型的Python实例讲解
Jun 27 #Python
结合Python的SimpleHTTPServer源码来解析socket通信
Jun 27 #Python
Python的Tornado框架的异步任务与AsyncHTTPClient
Jun 27 #Python
深入解析Python中的descriptor描述器的作用及用法
Jun 27 #Python
Python中的字符串查找操作方法总结
Jun 27 #Python
解析Python中的__getitem__专有方法
Jun 27 #Python
详解Python中的__getitem__方法与slice对象的切片操作
Jun 27 #Python
You might like
缅甸的咖啡简史
2021/03/04 咖啡文化
php cc攻击代码与防范方法
2012/10/18 PHP
PHP与Ajax相结合实现登录验证小Demo
2016/03/16 PHP
PHP在线打包下载功能示例
2016/10/15 PHP
php设计模式之原型模式分析【星际争霸游戏案例】
2020/03/23 PHP
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
jQuery的Ajax用户认证和注册技术实例教程(附demo源码)
2015/12/08 Javascript
JS获取字符串实际长度(包含汉字)的简单方法
2016/08/11 Javascript
javascript使用 concat 方法对数组进行合并的方法
2016/09/08 Javascript
Angular模版驱动表单的使用总结
2018/05/05 Javascript
微信小程序实现下拉菜单切换效果
2020/03/30 Javascript
vue组件文档(.md)中如何自动导入示例(.vue)详解
2019/01/25 Javascript
vue+Element实现搜索关键字高亮功能
2019/05/28 Javascript
JS图片懒加载技术实现过程解析
2020/07/27 Javascript
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
2020/09/21 Javascript
three.js显示中文字体与tween应用详析
2021/01/04 Javascript
[01:10:58]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
Python列表(list)、字典(dict)、字符串(string)基本操作小结
2014/11/28 Python
python用模块zlib压缩与解压字符串和文件的方法
2016/12/16 Python
深入浅出分析Python装饰器用法
2017/07/28 Python
python 日期操作类代码
2018/05/05 Python
对命令行模式与python交互模式介绍
2018/05/12 Python
Windows 64位下python3安装nltk模块
2018/09/19 Python
Django 路由控制的实现
2019/07/17 Python
Python 通过微信控制实现app定位发送到个人服务器再转发微信服务器接收位置信息
2019/08/05 Python
通过cmd进入python的步骤
2020/06/16 Python
Python如何读取、写入CSV数据
2020/07/28 Python
CSS3弹性伸缩布局之box布局
2016/07/12 HTML / CSS
NUK奶瓶美国官网:NUK美国
2016/09/26 全球购物
可贵的沉默教学反思
2014/02/06 职场文书
2014领导班子“四风问题”对照检查材料思想汇报(执法局)
2014/09/21 职场文书
2015年党员创先争优承诺书
2015/01/22 职场文书
红高粱观后感
2015/06/10 职场文书
瞿秋白纪念馆观后感
2015/06/10 职场文书
python获取淘宝服务器时间的代码示例
2021/04/22 Python
Python 数据科学 Matplotlib图库详解
2021/07/07 Python