Fixed security hole.

The file_storage.index() view function didn't sanitize its input. This made
is possible for an attacker to overwrite any file, including the files of
Pillar itself.
This commit is contained in:
2016-03-08 09:29:32 +01:00
parent bf614e0d54
commit 036116e2d3

View File

@@ -1,3 +1,4 @@
import logging
import os import os
import json import json
from multiprocessing import Process from multiprocessing import Process
@@ -7,7 +8,7 @@ from flask import Blueprint
from flask import abort from flask import abort
from flask import jsonify from flask import jsonify
from flask import send_from_directory from flask import send_from_directory
from flask import url_for from flask import url_for, helpers
from eve.methods.put import put_internal from eve.methods.put import put_internal
from application import app from application import app
from application.utils.imaging import generate_local_thumbnails from application.utils.imaging import generate_local_thumbnails
@@ -19,6 +20,9 @@ from application.utils.cdn import hash_file_path
from application.utils.gcs import GoogleCloudStorageBucket from application.utils.gcs import GoogleCloudStorageBucket
from application.utils.encoding import Encoder from application.utils.encoding import Encoder
log = logging.getLogger(__name__)
file_storage = Blueprint('file_storage', __name__, file_storage = Blueprint('file_storage', __name__,
template_folder='templates', template_folder='templates',
static_folder='../../static/storage',) static_folder='../../static/storage',)
@@ -104,22 +108,34 @@ def build_thumbnails(file_path=None, file_id=None):
@file_storage.route('/file', methods=['POST']) @file_storage.route('/file', methods=['POST'])
@file_storage.route('/file/<path:file_name>') @file_storage.route('/file/<path:file_name>', endpoint='index_with_path', methods=['GET', 'POST'])
def index(file_name=None): def index(file_name=None):
#GET file # GET file -> read it
if file_name: if request.method == 'GET':
return send_from_directory(app.config['STORAGE_DIR'], file_name) return send_from_directory(app.config['STORAGE_DIR'], file_name)
#POST file
# POST file -> save it
# Sanitize the filename; source: http://stackoverflow.com/questions/7406102/
file_name = request.form['name'] file_name = request.form['name']
keepcharacters = {' ', '.', '_'}
file_name = ''.join(c for c in file_name if c.isalnum() or c in keepcharacters).strip()
file_name = file_name.lstrip('.')
# Determine & create storage directory
folder_name = file_name[:2] folder_name = file_name[:2]
file_folder_path = os.path.join(app.config['STORAGE_DIR'], file_folder_path = helpers.safe_join(app.config['STORAGE_DIR'], folder_name)
folder_name)
if not os.path.exists(file_folder_path): if not os.path.exists(file_folder_path):
log.info('Creating folder path %r', file_folder_path)
os.mkdir(file_folder_path) os.mkdir(file_folder_path)
file_path = os.path.join(file_folder_path, file_name)
# Save uploaded file
file_path = helpers.safe_join(file_folder_path, file_name)
log.info('Saving file %r', file_path)
request.files['data'].save(file_path) request.files['data'].save(file_path)
return "{}", 200 # TODO: possibly nicer to just return a redirect to the file's URL.
return jsonify({'url': url_for('file_storage.index_with_path', file_name=file_name)})
def process_file(src_file): def process_file(src_file):