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 相关文章推荐
动态创建类实例代码
Oct 07 Python
Django 生成登陆验证码代码分享
Dec 12 Python
Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS浅析
May 08 Python
Python中使用Counter进行字典创建以及key数量统计的方法
Jul 06 Python
python去除拼音声调字母,替换为字母的方法
Nov 28 Python
Python3实现的旋转矩阵图像算法示例
Apr 03 Python
使用 Django Highcharts 实现数据可视化过程解析
Jul 31 Python
Python 日期的转换及计算的具体使用详解
Jan 16 Python
Python识别html主要文本框过程解析
Feb 18 Python
Python递归函数特点及原理解析
Mar 04 Python
解决pycharm中opencv-python导入cv2后无法自动补全的问题(不用作任何文件上的修改)
Mar 05 Python
对python中arange()和linspace()的区别说明
May 03 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
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
2014/06/30 PHP
PHP Opcache安装和配置方法介绍
2015/05/28 PHP
PHP ob缓存以及ob函数原理实例解析
2020/11/13 PHP
JS+CSS实现自动改变切换方向图片幻灯切换效果的方法
2015/03/02 Javascript
浅谈js图片前端预览之filereader和window.URL.createObjectURL
2016/06/30 Javascript
jQuery on()方法绑定动态元素的点击事件无响应的解决办法
2016/07/07 Javascript
需要牢记的JavaScript基础知识
2016/09/25 Javascript
10分钟掌握XML、JSON及其解析
2020/12/06 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
2016/11/18 Javascript
jQuery实现删除li节点的方法
2016/12/06 Javascript
如何将你的AngularJS1.x应用迁移至React的方法
2018/02/01 Javascript
vue 实现通过手机发送短信验证码注册功能
2018/04/19 Javascript
详解js中let与var声明变量的区别
2020/04/05 Javascript
在Layui中实现开关按钮的效果实例
2019/09/29 Javascript
JavaScript实现图片合成下载的示例
2020/11/19 Javascript
Python 用户登录验证的小例子
2013/03/06 Python
用Python实现服务器中只重载被修改的进程的方法
2015/04/30 Python
Python字符串、元组、列表、字典互相转换的方法
2016/01/23 Python
python中的字典使用分享
2016/07/31 Python
Python3.6笔记之将程序运行结果输出到文件的方法
2018/04/22 Python
Python爬虫小技巧之伪造随机的User-Agent
2018/09/13 Python
详解python编译器和解释器的区别
2019/06/24 Python
Dillard’s百货官网:Dillards.com
2018/05/26 全球购物
39美元购买一副眼镜或太阳镜:39DollarGlasses.com
2018/06/17 全球购物
真正的英国宝藏:Mappin & Webb
2019/05/05 全球购物
C++是不是类型安全的
2014/02/18 面试题
网络程序员自荐信
2014/01/25 职场文书
面临毕业的毕业生自荐书范文
2014/02/05 职场文书
转预备党员政审材料
2014/02/06 职场文书
离婚协议书范本样本
2014/08/19 职场文书
2014年客户经理工作总结
2014/11/20 职场文书
小学德育工作总结2015
2015/05/12 职场文书
2015年纪委工作总结
2015/05/13 职场文书
2016年幼儿园庆六一开幕词
2016/03/04 职场文书
七年级作文之《我和我的祖国》观后感作文
2019/10/18 职场文书
如何使JavaScript休眠或等待
2021/04/27 Javascript