diff options
| author | jvoisin | 2019-02-22 21:17:48 +0100 |
|---|---|---|
| committer | jvoisin | 2019-02-22 21:17:48 +0100 |
| commit | aee0940b511486b35ef2c2d0607f4cd2c0b50f23 (patch) | |
| tree | 9e20cac51df16c617b4cd089ce95495b546d29ef /main.py | |
| parent | 12be535945cbfbf0aa8ca149348b0eb683a23d5b (diff) | |
Mitigate filename-based race conditions
Diffstat (limited to 'main.py')
| -rw-r--r-- | main.py | 24 |
1 files changed, 19 insertions, 5 deletions
| @@ -1,4 +1,6 @@ | |||
| 1 | import os | 1 | import os |
| 2 | import hashlib | ||
| 3 | import hmac | ||
| 2 | 4 | ||
| 3 | from libmat2 import parser_factory | 5 | from libmat2 import parser_factory |
| 4 | 6 | ||
| @@ -13,13 +15,20 @@ app.config['SECRET_KEY'] = os.urandom(32) | |||
| 13 | app.config['UPLOAD_FOLDER'] = './uploads/' | 15 | app.config['UPLOAD_FOLDER'] = './uploads/' |
| 14 | app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB | 16 | app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB |
| 15 | 17 | ||
| 16 | mimetypes = 'image/jpeg, image/png' | 18 | def __hash_file(filepath: str) -> str: |
| 19 | sha256 = hashlib.sha256() | ||
| 20 | with open(filepath, 'rb') as f: | ||
| 21 | while True: | ||
| 22 | data = f.read(65536) # read the file by chunk of 64k | ||
| 23 | if not data: | ||
| 24 | break | ||
| 25 | sha256.update(data) | ||
| 26 | return sha256.hexdigest() | ||
| 17 | 27 | ||
| 18 | 28 | ||
| 19 | @app.route('/download/<string:filename>') | 29 | @app.route('/download/<string:key>/<string:filename>') |
| 20 | def download_file(filename:str): | 30 | def download_file(key:str, filename:str): |
| 21 | if filename != secure_filename(filename): | 31 | if filename != secure_filename(filename): |
| 22 | flash('naughty naughty') | ||
| 23 | return redirect(url_for('upload_file')) | 32 | return redirect(url_for('upload_file')) |
| 24 | 33 | ||
| 25 | filepath = secure_filename(filename) | 34 | filepath = secure_filename(filename) |
| @@ -27,6 +36,9 @@ def download_file(filename:str): | |||
| 27 | complete_path = os.path.join(app.config['UPLOAD_FOLDER'], filepath) | 36 | complete_path = os.path.join(app.config['UPLOAD_FOLDER'], filepath) |
| 28 | if not os.path.exists(complete_path): | 37 | if not os.path.exists(complete_path): |
| 29 | return redirect(url_for('upload_file')) | 38 | return redirect(url_for('upload_file')) |
| 39 | if hmac.compare_digest(__hash_file(complete_path), key) is False: | ||
| 40 | print('hash: %s, key: %s' % (__hash_file(complete_path), key)) | ||
| 41 | return redirect(url_for('upload_file')) | ||
| 30 | 42 | ||
| 31 | @after_this_request | 43 | @after_this_request |
| 32 | def remove_file(response): | 44 | def remove_file(response): |
| @@ -72,7 +84,9 @@ def upload_file(): | |||
| 72 | meta_after = parser.get_meta() | 84 | meta_after = parser.get_meta() |
| 73 | os.remove(filepath) | 85 | os.remove(filepath) |
| 74 | 86 | ||
| 75 | return render_template('download.html', mimetypes=mimetypes, meta=meta, filename=output_filename, meta_after=meta_after) | 87 | key = __hash_file(os.path.join(app.config['UPLOAD_FOLDER'], output_filename)) |
| 88 | |||
| 89 | return render_template('download.html', mimetypes=mimetypes, meta=meta, filename=output_filename, meta_after=meta_after, key=key) | ||
| 76 | 90 | ||
| 77 | return render_template('index.html', mimetypes=mimetypes) | 91 | return render_template('index.html', mimetypes=mimetypes) |
| 78 | 92 | ||
