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用Pygal如何生成漂亮的SVG图像详解
Feb 10 Python
Python常用内置模块之xml模块(详解)
May 23 Python
浅析Python中return和finally共同挖的坑
Aug 18 Python
python线程池threadpool使用篇
Apr 27 Python
python 执行shell命令并将结果保存的实例
May 11 Python
详解Python中的type和object
Aug 15 Python
Jupyter notebook在mac:linux上的配置和远程访问的方法
Jan 14 Python
python函数修饰符@的使用方法解析
Sep 02 Python
python3.7将代码打包成exe程序并添加图标的方法
Oct 11 Python
Django CBV模型源码运行流程详解
Aug 17 Python
Python内置函数及功能简介汇总
Oct 13 Python
python 提取html文本的方法
May 20 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 jquery 实现新闻标签分类与无刷新分页
2009/12/18 PHP
PHP+memcache实现消息队列案例分享
2014/05/21 PHP
Codeigniter检测表单post数据的方法
2015/03/21 PHP
PHP使用 Pear 进行安装和卸载包的方法详解
2019/07/08 PHP
js 替换功能函数,用正则表达式解决,js的全部替换
2010/12/08 Javascript
通过Jscript中@cc_on 语句识别IE浏览器及版本的代码
2011/05/07 Javascript
基于jquery实现的一个选择中国大学的弹框 (数据、步骤、代码)
2012/07/26 Javascript
js弹出层永远居中实现思路及代码
2013/11/29 Javascript
jQuery中:gt选择器用法实例
2014/12/29 Javascript
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现
2015/03/05 Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
2015/12/29 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
最常用的jQuery表单验证(简单)
2017/05/23 jQuery
nodejs基于mssql模块连接sqlserver数据库的简单封装操作示例
2018/01/05 NodeJs
深入理解nodejs搭建静态服务器(实现命令行)
2019/02/05 NodeJs
vue-router 起步步骤详解
2019/03/26 Javascript
React中阻止事件冒泡的问题详析
2019/04/12 Javascript
JS拖动选择table里的单元格完整实例【基于jQuery】
2019/05/28 jQuery
js如何验证密码强度
2020/03/18 Javascript
利用Python演示数型数据结构的教程
2015/04/03 Python
python计算对角线有理函数插值的方法
2015/05/07 Python
Python的Django框架中的URL配置与松耦合
2015/07/15 Python
Python实现excel转sqlite的方法
2017/07/17 Python
CentOS 7下安装Python3.6 及遇到的问题小结
2018/11/08 Python
python 图片去噪的方法示例
2019/07/09 Python
python matplotlib库绘制散点图例题解析
2019/08/10 Python
python基于opencv实现人脸识别
2021/01/04 Python
Origins悦木之源英国官网:雅诗兰黛集团高端植物护肤品牌
2017/11/06 全球购物
欧洲领先的火车票和大巴票预订平台:Trainline
2018/12/26 全球购物
印度在线购物网站:Paytmmall
2019/07/24 全球购物
注塑工厂厂长岗位职责
2013/12/02 职场文书
十佳中学生事迹材料
2014/06/02 职场文书
工作失职造成投诉的检讨书范文
2014/10/05 职场文书
公务员政审材料
2014/12/23 职场文书
酒店前台辞职书
2015/02/26 职场文书
游戏《我的世界》澄清Xbox版暂无计划加入光追
2022/04/03 其他游戏