Secure File Handling in Flask Applications

Tutorial 5 of 5

1. Introduction

In this tutorial, we'll focus on secure file handling in Flask applications. We will equip you with the knowledge and skills necessary to protect your Flask applications from potential vulnerabilities associated with file handling.

By the end of this tutorial, you should be able to:
- Understand the concept of secure file handling in Flask.
- Implement secure file handling in your Flask application.

Prerequisites: Basic understanding of Python and Flask framework is required. Knowledge of HTML is a plus but not mandatory.

2. Step-by-Step Guide

Flask is a micro web framework written in Python. It does not include functionalities for handling file uploads by default. However, the Flask-Uploads extension can be used to manage file uploads.

Secure File Handling Concepts

The primary considerations when handling file uploads in a secure manner are:
1. File Type Validation: Only allow upload of files with certain extensions.
2. File Size Validation: Limit the size of uploaded files.
3. File Path Validation: Never use user input to determine the file path.

Best Practices and Tips

  • Always validate the file on the server, even if it's already validated on the client-side.
  • Store the files in a directory outside of the webroot to prevent direct access.
  • Rename the files upon upload to prevent any code execution attempts.

3. Code Examples

Here is a basic example of file handling in Flask.

Example 1:

from flask import Flask, request
from werkzeug.utils import secure_filename

app = Flask(__name__)

@app.route('/upload', methods = ['GET', 'POST'])
def upload_file():
   if request.method == 'POST':
      f = request.files['file']
      f.save(secure_filename(f.filename))
      return 'file uploaded successfully'

if __name__ == '__main__':
   app.run(debug = True)

In this code:
- We're using the secure_filename() function from the werkzeug.utils module, which ensures a secure filename.
- When a file is uploaded via the '/upload' route, it is securely saved in the application's root directory.
- The expected result is a message indicating successful upload.

Example 2:

from flask import Flask, request, abort
from werkzeug.utils import secure_filename
import os

app = Flask(__name__)

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        abort(400, 'No file part in the request.')

    f = request.files['file']

    if f.filename == '':
        abort(400, 'No selected file.')

    if not allowed_file(f.filename):
        abort(400, 'File type not allowed. Allowed extensions: txt, pdf, png, jpg, jpeg, gif.')

    filename = secure_filename(f.filename)
    f.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
    return 'File uploaded successfully!'

def allowed_file(filename):
    ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

if __name__ == '__main__':
    app.config['UPLOAD_FOLDER'] = '/path/to/upload/directory'
    app.run(debug=True)

In this code:
- We first check if the post request has the file part.
- Then, we validate the filename using the allowed_file function.
- If the file is valid, we save it to a specified upload directory.

4. Summary

In this tutorial, we've discussed how to handle file uploads securely in Flask applications. We've covered validating file types, file paths, and file sizes. We've also looked into the best practices for secure file handling.

5. Practice Exercises

  1. Create a Flask application that allows users to upload a profile picture. Ensure that only image files (jpeg, png, gif) of a certain size are accepted.
  2. Create a Flask application that allows users to upload a PDF file. The file should be renamed upon upload based on the current timestamp.
  3. Create a file download endpoint that allows users to download an uploaded file. Ensure that the file path is not exposed to the user.

These exercises will help you put to practice what you've learned. Remember to always validate the file on the server-side, limit the size of the files, and never use user input to determine the file path. Happy coding!