How to install an antivirus in Laravel in 10 mins
If you are working on a product where user can upload some files, it is very important to check if them are malicious or not. A malicious file could be very dangerous, not only for your server, but also for your users.
A malicious user may want to upload a malicious file in order to try a server side execution. Imagine if the file is a script capable of removing each stored file (also from other users). This will break your application and will cause a damage for your users.
Or, a malicious user that has the credential of a real one, upload the malicious file, and waits for the real user to download and execute it.
Malicious file are not only scripts like Bash, PHP or Python; they can appear in a form of a PDF or an image. This means that checking the extension and the mime type is not sufficient.
In this article we will explore a way to install an antivirus on a Laravel application and we will see a really simple implementation.
We will use clamav-validator, a ready to use package which uses an open source antivirus called ClamAV to perform the file scan.
Install the antivirus
Before all, you have to install the antivirus in your machine. This means that every server must have the antivirus installed, otherwise the package will not work.
The following code will install and enable the antivirus.
# Install clamav virus scanner
sudo apt-get update && sudo apt-get install -y clamav-daemon
# Update virus definitions
sudo freshclam
# Start the scanner service
sudo systemctl enable --now clamav-daemon clamav-freshclam
Fix on Ubuntu 20.04 (Clamd was NOT notified)
If you are seeing an error like Clamd was NOT notified: Can't connect to clamd through /var/run/clamav/clamd.ctl: No such file or directory
, you can try the following:
sudo systemctl stop clamav-daemon.service
sudo rm /var/log/clamav/freshclam.log
sudo systemctl start clamav-daemon.service
Install the package
In the project folder, start a new terminal and run the installation through composer.
composer require sunspikes/clamav-validator
Use an env variable to choose if the scan must be performed
In this case, I publish the configuration file to skip the validation on default, so I have to add in the .env
file a CLAMAV_SKIP_VALIDATION=false
to tell it has to do the validation. If the value is true
, it will skip the validation, so it is not needed to have the antivirus installed.
I want to skip the scan by default because I prefer explicit behaviour over implicit ones.
So, to publish the configuration:
php artisan vendor:publish --provider="Sunspikes\ClamavValidator\ClamavValidatorServiceProvider" --tag=config
Now edit the config/clamav.php
file and set the default value for skip_validation
to true
.
It should change from:
'skip_validation' => env('CLAMAV_SKIP_VALIDATION', false),
to:
'skip_validation' => env('CLAMAV_SKIP_VALIDATION', true),
Now, it is sufficient to add CLAMAV_SKIP_VALIDATION=false
to be able to scan a file.
Perform a file scan
You have installed ClamAV and the relative package, so it is time to check if a file is a virus.
This package is built to check if an uploaded file is malicious or not, so it provides a really simple utility during validation. In fact, it is sufficient to add a specific rule during the request validation.
The following code is responsible to perform the file scan:
public function store(Request $request): JsonResponse
{
if ($request->hasFile('attachment')) {
$request->validate(['attachment' => 'clamav']);
}
// handle the attachment
You can use also in custom requests, but it is sufficient to add the rule clamav
in the validation to automatically perform the scan. If the file contains suspicious content, it will produce the following error message: “attachment contains virus”.
Clearly, you can also change the message and add a translation. It is possible to publish language files using the following command:
php artisan vendor:publish --provider="Sunspikes\ClamavValidator\ClamavValidatorServiceProvider" --tag=lang
✅ Congratulations! You learned how to perform an antimalware scan on a file!