How To Encrypt Large Files in Laravel
By: Costin Soare
Tags: Encryption, Laravel, PHP, Programminig, Security

Tutorial

In this tutorial, I will describe all the steps needed to encrypt large files into a brand new Laravel project.

First, create a new Laravel project using the Laravel installer. We’ll call it security-app :

laravel new security-app

At the time of writing this tutorial, we are using Laravel v6.5.2.

Because we have used the Laravel installer, we already have an application key generated and added to our .env file. If you are using other installation methods, don’t forget to generate a new app key using:

php artisan key:generate

Because we are using Laravel Valet, we should already have the security-app.test domain created for us. If you are using another development environment, you should add a local domain to point to the new project.

Since the front-end scaffolding has been moved to Laravel UI since v6, we will install the laravel/ui package.

composer require laravel/ui — dev

Next, we will install the bootstrap and auth scaffolding:

php artisan ui bootstrap --auth

And compile everything.

npm install && npm run dev

We also need to configure our database access credentials in the .env file and run the initial migrations:

php artisan migrate

We can now create a new user and log in to see the user dashboard.

Note: For the purpose of this demonstration, we will create a basic upload form, but in your application, you should consider using a more sophisticated upload functionality, using chunked uploads for large files.

A very good package that you can use for this purpose is pion/laravel-chunk-upload.

Laravel auth scaffolding has created for us a /home route, a HomeController , and a home.blade.php view file.

Let’s edit the home.blade.php file and add a form and an upload field:

Next, we will add a new route:

Route::post(‘/home’, ‘HomeController@store’)->name(‘uploadFile’);

And a new store method to the HomeController . This method will store the uploaded file in a subdirectory with the current user ID, within a files directory ( storage/app/files/{user-id} ).

Note: This is poor practice and should not be used in a production app. We are relying on the filesystem to get a user’s files for demonstration purposes to keep this tutorial small, but a more robust system using database tables for keeping track of each user’s files is required in a production app.

This is the stage where we need to encrypt the user uploaded files. We will pull in the file-vault package:

composer require soarecostin/file-vault

The package allows access to the FileVault facade, which exposes a few methods for encrypting and decrypting a file, as well as a few methods to set options like a different encryption key for each file, or specifying the Laravel filesystem disk that the file belongs to.

We will use the FileVault::encrypt($file) method to encrypt our user-uploaded file. This function will delete the original unencrypted file, and replace it with a file with the same name and an additional .enc extension.

If you would like to name your file differently, you can pass in the desired name as the second parameter to the encrypt method. If you’d like to preserve your original file, you can use the encryptCopy method.

This is what our store method looks like now:

Next, we need to see all of the user-uploaded files and we also need a way of downloading them.

We will create a new downloadFile route and a new downloadFile method in HomeController :

Route::get(‘/files/{filename}’, ‘HomeController@downloadFile’)->name(‘downloadFile’);

The downloadFile method uses the Laravel native streamDownload response, which accepts a callback.

Inside the callback, we are calling the streamDecrypt method of the FileVault facade provided by the package, which will decrypt the file and serve it segment-by-segment to the streamDownload method, allowing your users to download the decrypted file directly.

We now need to display all the user’s files below the upload form. For this, we will send a $files variable from the index method of HomeController to the home.blade.php view file and display the user’s files in the home.blade.php file, below the upload form.

This is it! We are now using encryption at rest! We’ve created a form for users to upload files, we are encrypting those files, and we are only decrypting them when requested by the user who uploaded them.

Of course, in production, more security measures are needed, and the FileVault package is designed to help you in that regard.

For example, you may want to store your user-uploaded large files in Amazon S3, which the package supports for encrypting/stream-decrypting files.

You may also want to use a different encryption key for each user or each file, which is also possible with the FileVault package.