首页 > 解决方案 > 如何从特定目录停用或停止脚本执行

问题描述

我有一个目录,其中包含用户上传的脚本、Python、Js 等,但由于担心安全漏洞,我想停用此类目录中的这些脚本以限制它们执行。

我想使用 python 烧瓶来做到这一点(Python 3)。

标签: pythonflask

解决方案


如果我正确理解问题,您希望允许用户将任意文件上传到您的服务器。一个好主意是在将文件保存到服务器之前创建一个安全的文件名。官方文档建议使用secure_filename来实现这一点,但也指出,如果服务器执行文件(例如“php”),您可能需要禁止某些扩展名。

(假设您使用的是 SQLAlchemy)

您可以创建一个模型来存储有关文件的自定义文件名和元数据。下面是一个示例应用程序,使用了官方文档中的一些代码。

from flask import (Flask, request,
    send_from_directory, abort, redirect)
from werkzeug.utils import secure_filename
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = 'change'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000

db = SQLAlchemy()
db.init_app(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    uploaded_files = db.relationship('UserFile', backref='user')

class UserFile(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(50))
    client_filename = db.Column(db.String(100))
    ... #other file info
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

@app.before_first_request
def create_tables():
    db.create_all()

@app.route('/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            return redirect(request.url)
        file = request.files['file']
        # If the user does not select a file, the browser submits an
        # empty file without a filename.
        if file.filename == '':
            return redirect(request.url)
        if file:
            filename = f"{str(uuid4())}.txt"
            db.session.add(UserFile(
                filename=filename,
                client_filename = secure_filename(file.filename) #minimize security issues in the future
                #user_id = however you determine who the user is
            ))
            db.session.commit()
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

@app.route('/files/<int:id_>/download')
def file_download(id_):
    user_file = UserFile.query.get(id_)
    if not user_file:
        abort(404)
    return send_from_directory(app.config['UPLOAD_FOLDER'], user_file.filename, 
        attachment_filename = user_file.client_filename,
        as_attachment=True)

if __name__ == '__main__':
    app.run('localhost', port=5000, debug=True)

推荐阅读