Flask Python 3 Secure User Uploads File

Providing an like shooting fish in a barrel method for collaborators to upload files to a filestore without the need for them to understand whatever lawmaking whatsoever

Photograph by Howdy I'grand Nik 🎞 on Unsplash

When edifice a webserver we often wish to present an thought or topic. In the example of a static website, this can be done past including the relevant information within the source files. In more dynamic examples, an API (application programming interface) tin can exist used to pre-process information before returning it to the user.

In this example, we pattern a unproblematic flask app which only requires a user primal and a web browser to work. The idea backside this is that anyone tin can utilise it, and it is a device (and operating system), independent.

Creating the flask app

As usual, we commencement by installing the relevant libraries for the server. The simplest way to do this is through the apply of pip (pythons package manager).

            pip install flask, werkzeug          

The upload-page template

Next, create our HTML template for the login page. To practice this we offset in our application directory and brand a new file named templates . Within this, nosotros create a file named upload.html and paste the following lawmaking within it.

In essence, we take a form which contains our password input, a file upload input and a submit button. When working this will expect as follows

Output from upload_simple.html

Setting up the upload options

Next, we define a config file for our upload options. To exercise this create a file named config.py in your main app folder. Within this, we can specify a maximum accustomed file size, the upload destination, and what file extensions we can cull to take. Copy the code below into config.py and conform accordingly.

A notation on file types: File extensions do not guarantee file type and nosotros should avert executing any uploaded files. This is why we later introduce a password — such that but approved users can upload.

A flask template

We begin with a bones flask template, which imports our information and serves the upload.html page when navigating to http://127.0.0.1:4000/upload

Upload file checks

Now we have our app, we tin add a number of functions to ensure that nosotros take the right directory, and if not create it.

            if not os.path.isdir(upload_dest):
os.mkdir(upload_dest)

Nosotros tin can set the maximum file upload size (using the value from config.py)

            app.config['MAX_CONTENT_LENGTH'] = file_mb_max * 1024 * 1024          

and also bank check the file extensions (once more defined in config.py)

            def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[ane].lower() in extensions

Personally, I have added these betwixt app.secret and the @app.route sections within the lawmaking.

What to do on upload

Finally, we have withal to tell the program what to practise upon uploading. We do so this by parsing the post asking from the upload page. For information on what this means — take a read of:

Here we cheque if the asking.method is a POST, and if then handle any files attached. The showtime section deals with an empty asking, whilst the second iterates through each file, checks that they have the correct file extension, and if so saves them to our desired location (upload_dest).

            @app.route('/upload', methods=['Mail service'])
def upload_file():
if request.method == 'Mail':
if 'files[]' not in asking.files:
flash('No files found, effort over again.')
return redirect(request.url)
files = request.files.getlist('files[]') for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.salvage(os.path.bring together( upload_dest, filename))
flash('File(due south) uploaded')
return redirect('/upload')

Testing the usage case

Finally, before standing on to calculation passwords, we want to make sure that the upload functions as intended. To practise this we run the python script, navigate to http://127.0.0.1:4000/upload, select a few files and click upload. If this has been successful, and yous are using the configuration above, your files should now reside within an uploads_folder directory nested in the aforementioned binder as your app.

Calculation an encrypted database for user authentication

And so far we take created a Flask app which we tin can use to upload files. Adjacent, we want to add a layer of basic security, such that nosotros tin can track what files accept been uploaded and by whom. In addition, this allows usa to pass up anyone not authorised to commit data to the directory.

Installing pysqlcipher3

We begin by installing our database tool. This tin can sometimes cause bug for people, so the installation instructions for Mac and Linux have been included below.

MAC

            brew install SQLCipher
pip install pysqlcipher3

LINUX

            sudo apt install sqlcipher libsqlcipher0 libsqlcipher-dev
sudo -H pip3 install pysqlcipher3
python3 -c 'import pysqlcipher3; print(pysqlcipher3.__path__)'

Connecting to the database

We get-go by connecting to the database. If you accept ever used databases before, the pysqlcipher syntax is pretty much the same as sqlite, or any postgresql libraries. We begin by importing the libraries

            from pysqlcipher3 import dbapi2 as sqlite3
from config import app_key, db_loc

And then connecting to the database:

            conn = sqlite3.connect(db_loc)# where this is /path/examination.db
cursor = conn.cursor()

Finally, nosotros need to specify an encryption key for our database in order to be able to admission the data.

            cursor.execute("PRAGMA key='%southward'"%app_key)          

If you do non exercise this, or use a different central, you volition receive the post-obit error: DatabaseError: file is not a database when trying to read data from the database schema.

Creating the Database

Having opened our database, and entered our key, we tin can now create a table to store our values. We do this by executing a create table SQL control with the cursor execute function. The simplest usage case would require a proper name and an upload_key.

            cursor.execute(
'''
CREATE TABLE IF Not EXISTS upload (
id INTEGER NOT NULL PRIMARY Fundamental AUTOINCREMENT,
proper noun TEXT NOT Naught,
upload_key TEXT UNIQUE
);
'''
)

Additionally, I have gear up a status that each primal has to be unique, as we are not using a user name to log on.

Finally, we have to commit our new tabular array to the database and close it.

            conn.commit()
## conn.shut()
## close but when we have finished everything, otherwise nosotros accept to reopen the database each time

Adding a User

We demand users to be able to use the upload tool, and then we tin can add some using the insert command.

            cursor.execute(
'''
INSERT INTO upload (proper noun, dir, uploadcode)
VALUES ("bob", "bobs elevation clandestine upload key")
'''
conn.commit()

Reading the Database

Equally a bank check, nosotros want to see if at that place is a name associated with the upload_key. This can exist washed with the select function, coupled with a where conditional.

            user_code = 'bobs top secret upload key'            cursor.execute('select              * from upload              where              uploadcode="%south"'%user_code)            upshot = cursor.fetchall() # become all the results e.thousand. [("bob",)]          

Stringing it all together

Now we take a database and an upload script, we can combine the ii.

Opening the database

Firstly we add together the required library

            from pysqlcipher3 import dbapi2 every bit sqlite3
# from config import app_key, db_loc # already imported

under the from config_simple import *line.

Reading the countersign

If y'all are using the HTML lawmaking from earlier, nosotros already take a password input field :<p> upload_key: <input proper noun="psw" type="password" /></p>

As this is within the submission class nosotros can read information technology as function of the Postal service request in the @app.route wrapper.

            user_code = str(asking.form.become('psw'))          

We combine this with our database read to course a conditional checking if there is anyone with that access primal /countersign.

            cursor.execute('select * from upload where uploadcode="%southward"'%user_code)
result = cursor.fetchall()
if len(result)==0:
flash('Not a valid Code')
return redirect(request.url)

However, since the database can only be opened and read from the aforementioned computational thread as the website we demand to identify

            conn = sqlite3.connect(db_loc)
cursor = conn.cursor()
cursor.execute("PRAGMA key='%s'"%app_key)

earlier the cursor.execute block, and a conn.close() afterward the outcome = line. (see app.py in the GitHub repo at the cease)

Conclusion

And in that location nosotros accept it — the most basic of submission boxes which allows for the uploading of files past pre-canonical users. There are withal a number of improvements that yous may wish to make (these are all in the additional files shown in the GitHub repository below).

  • Checking the filename cord for an extension can cause bug. Files may be named incorrectly, or even non take an extension (every bit was the example with many of my files). Instead, nosotros can filter on the file.mimetype values. These are of the format image/png etc.
  • Drag and Drop uploading. It tin frequently exist cumbersome to manually select files, particularly if they are in different locations. Dragging them from a file browser makes life much simpler for the user.
  • Automatic uploads. Another common mistake is to select a file, simply forget to click submit. Having a window that works immediately after you driblet a file in it can help assist productivity and user satisfaction
  • File previews. If the user is uploading images, it tin always be helpful to have miniature previews available. This allows a terminal-minute check such that you are not repeatedly submitting the same file.
  • File failure indicators. Although there is a message informing us of the upload status, a visual cue (ie a lighter preview paradigm) makes it much easier to see if something has not worked.
  • Unique download spaces — if you lot accept many users, it can go confusing which file belongs to who (non to mention the overwriting problem). Instead, we tin add a designated space for each user, and salvage the paths within the database.

Adding all the additional suggestions above and nosotros the following output.

Here nosotros see, two files have failed, with one succeeding in the middle. In this case, it was due to invalid user credentials and an intentionally invalid filetype.

Disclaimer: this is not the most secure method of checking credentials, however for the purposes of many tasks it tin exist a perfectly adequate solution.

Codebase

All the example code for this tutorial has been dumped (quite literally) into a Github repository.

If you lot have any improvements, experience gratis to submit a pull asking.

flynnrequed.blogspot.com

Source: https://towardsdatascience.com/writing-a-multi-file-upload-python-web-app-with-user-authentication-8f75064b819a

0 Response to "Flask Python 3 Secure User Uploads File"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel