Scan File(s) For The Virus Before Uploading To Server Using .NET 5.0

This article will demonstrate about the what is the easiest way to protect our files/documents from viruses before they got uploaded to a storage location. Usually, without performing anti-virus scanning or other content checking against the uploaded file, there might be a chance that attackers could target other users of the application by uploading malware to the server.
 
In today's article, we will perform filtering and content checking on any files which are uploaded to the server. Files should be thoroughly scanned and validated against an anti-virus scanner with up-to-date virus signatures before being made available to other users. Any files flagged as malicious should be discarded or deleted immediately.
 
Prerequisites
 
I've been using the .Net 5.0 template to perform this operation and here I'm sharing the link to install the SDK,
Source Code - Github Repo
 
Step 1
 
Create a Web API project with a .Net 5.0 Template.
 
Step 2 
 
Install the Package which will be used for the virus when uploading any document to the API endpoint.
 
Scan File(s) For The Virus Before Uploading To Server Using .NET 5.0
 
For more details about nclam & Clam Av, you can check here.
 
Step 3 
 
There are two possible ways in which we can use this Clam AV Server in our project,
  1. Running the Clam Av Server under the Docker image
  2. Using their own Clam Av Ip address to scan our files (If clam server is already installed in our machine)

Running the Clam Av Server under the Docker image 

 
Setup the Clam server - in local using Docker
  1. Click here to install the docker.
  2. Use the below commands in command prompt to setup the clam Av server locally 
    • docker run -d -p 3310:3310 mkodockx/docker-clamav:alpine
    • docker run -d -p 3310:3310 mk0x/docker-clamav
    • docker ps
Scan File(s) For The Virus Before Uploading To Server Using .NET 5.0
 
Once this setup is done, let's create an endpoint and the necessary configuration to scan our files under that clam Av server by docker image. Add the Clam Av port configuration in the appsettings.json file.
 
appsettings.json 
  1. {  
  2.   "Logging": {  
  3.     "LogLevel": {  
  4.       "Default""Information",  
  5.       "Microsoft""Warning",  
  6.       "Microsoft.Hosting.Lifetime""Information"  
  7.     }  
  8.   },  
  9.   "AllowedHosts""*",  
  10.   "ClamAVServer": {  
  11.     "URL""localhost",  
  12.     "Port""3310"  
  13.   }  
  14. }  
Create an endpoint and read the file from the file upload endpoint and convert the file to a byte array. ClamClient scan result returns with ClamScanResult enum values which tells you that your scan was clean or a virus was detected.
 
Here is some sample code,
 
FileController.cs
  1. using Microsoft.AspNetCore.Http;  
  2. using Microsoft.AspNetCore.Mvc;  
  3. using Microsoft.Extensions.Configuration;  
  4. using Microsoft.Extensions.Logging;  
  5. using nClam;  
  6. using System;  
  7. using System.Collections.Generic;  
  8. using System.IO;  
  9. using System.Linq;  
  10. using System.Net;  
  11. using System.Threading.Tasks;  
  12.   
  13. namespace ScanFiles_AntiVirus.Controllers  
  14. {  
  15.     [Route("api/[controller]")]  
  16.     [ApiController]  
  17.     public class FileUploadController : ControllerBase  
  18.     {  
  19.         private readonly IConfiguration _configuration;  
  20.         public FileUploadController(  
  21.             IConfiguration configuration)  
  22.         {  
  23.             _configuration = configuration;  
  24.         }  
  25.   
  26.         [HttpPost]    
  27.         public async Task<IActionResult> UploadFile(IFormFile file)  
  28.         {  
  29.             if (file == null || file.Length == 0)  
  30.                 return Content("file not selected");  
  31.   
  32.             var ms = new MemoryStream();  
  33.             file.OpenReadStream().CopyTo(ms);  
  34.             byte[] fileBytes = ms.ToArray();  
  35.             string Result = string.Empty;  
  36.             try  
  37.             {  
  38.                 var clam = new ClamClient(this._configuration["ClamAVServer:URL"],  
  39.                 Convert.ToInt32(this._configuration["ClamAVServer:Port"]));  
  40.                 var scanResult = await clam.SendAndScanFileAsync(fileBytes);  
  41.   
  42.                 // Switch Expression C# 8.0   
  43.                 Result =  scanResult.Result switch  
  44.                 {  
  45.                     ClamScanResults.Clean => "Clean",  
  46.                     ClamScanResults.VirusDetected => "Virus Detected",  
  47.                     ClamScanResults.Error => "Error in File",  
  48.                     ClamScanResults.Unknown => "Unknown File",  
  49.                           _ => "No case available"  
  50.                 };  
  51.             }  
  52.             catch (Exception ex)  
  53.             {  
  54.                 throw ex;  
  55.             }  
  56.   
  57.             return Ok(Result);  
  58.         }  
  59.     }  
  60. }  
Run and Test with Valid File,
 
Scan File(s) For The Virus Before Uploading To Server Using .NET 5.0
 
Test with Anti-malware File
 
As a POC, the EICAR file was uploaded. This is a sample file used to test the response of anti-virus software. You can download a sample file from this Site. You may need to pause your antivirus protection on your device to perform this activity. 
 
Scan File(s) For The Virus Before Uploading To Server Using .NET 5.0
 
Using their own Clam Av Ip address to scan our files
 
To scan the documents without docker image and if the clam av server is already installed in our machine we need to change a bit of code in the API level instead of going with docker port.
 
Here is the following code,
 
FileController.cs
  1. using Microsoft.AspNetCore.Http;  
  2. using Microsoft.AspNetCore.Mvc;  
  3. using Microsoft.Extensions.Configuration;  
  4. using Microsoft.Extensions.Logging;  
  5. using nClam;  
  6. using System;  
  7. using System.Collections.Generic;  
  8. using System.IO;  
  9. using System.Linq;  
  10. using System.Net;  
  11. using System.Threading.Tasks;  
  12.   
  13. namespace ScanFiles_AntiVirus.Controllers  
  14. {  
  15.     [Route("api/[controller]")]  
  16.     [ApiController]  
  17.     public class FileUploadController : ControllerBase  
  18.     {  
  19.         private readonly IConfiguration _configuration;  
  20.         public FileUploadController(  
  21.             IConfiguration configuration)  
  22.         {  
  23.             _configuration = configuration;  
  24.         }  
  25.   
  26.         [HttpPost]    
  27.         public async Task<IActionResult> UploadFile(IFormFile file)  
  28.         {  
  29.             if (file == null || file.Length == 0)  
  30.                 return Content("file not selected");  
  31.   
  32.             var ms = new MemoryStream();  
  33.             file.OpenReadStream().CopyTo(ms);  
  34.             byte[] fileBytes = ms.ToArray();  
  35.             string Result = string.Empty;  
  36.             try  
  37.             {  
  38.                 // Scan with Docker image  
  39.                 //var clam = new ClamClient(this._configuration["ClamAVServer:URL"],  
  40.                 //Convert.ToInt32(this._configuration["ClamAVServer:Port"]));  
  41.   
  42.                 // Scan with Clam Av server  
  43.                 var clam = new ClamClient(IPAddress.Parse("127.0.0.1"), 3310);  
  44.                 var scanResult = await clam.SendAndScanFileAsync(fileBytes);  
  45.   
  46.                 // Switch Expression C# 8.0   
  47.                 Result =  scanResult.Result switch  
  48.                 {  
  49.                     ClamScanResults.Clean => "Clean",  
  50.                     ClamScanResults.VirusDetected => "Virus Detected",  
  51.                     ClamScanResults.Error => "Error in File",  
  52.                     ClamScanResults.Unknown => "Unknown File",  
  53.                           _ => "No case available"  
  54.                 };  
  55.             }  
  56.             catch (Exception ex)  
  57.             {  
  58.                 throw ex;  
  59.             }  
  60.   
  61.             return Ok(Result);  
  62.         }  
  63.     }  
  64. }  

Conclusion

 
Thank you for reading, please let me know your questions, thoughts, or feedback in the comments section. I appreciate your feedback and encouragement.
 
keep learning....!