Build a Secure File Upload and Download System with Encryption in Spring Boot

In today’s digital landscape, securing user data is paramount. One effective way to achieve this is by implementing a secure file upload and download system with encryption in your applications. In this blog post, we will explore best practices and step-by-step instructions to create such a system using Spring Boot. Whether you’re a seasoned developer or just starting, this guide will help you ensure that your files are securely handled and protected from unauthorized access.

Why You Need a Secure File Upload and Download System

With increasing concerns about data breaches and privacy violations, it is crucial to have a robust file management system in place. Here are some reasons why security is vital:

  • Protect Sensitive Data: Encrypting files ensures that sensitive information remains confidential, even if unauthorized access occurs.
  • Compliance: Many industries have regulations requiring secure data handling. Implementing a secure system helps you stay compliant.
  • User Trust: Providing a secure experience builds trust with your users, making them more likely to engage with your application.

Best Practices for Secure File Upload and Download

1. Validate File Types and Sizes

Always validate the types and sizes of files uploaded to your server. Use a whitelist approach, allowing only specific file formats (e.g., PDF, images) and set a maximum file size limit to mitigate risks associated with large file uploads.

2. Store Files Securely

Store uploaded files outside of the web server’s root directory to prevent direct access. Organize files into subdirectories based on user or session information to maintain structure and avoid filename clashes.

3. Use Strong Encryption

Encrypt files before saving them on the server. Implement strong encryption algorithms like AES and manage encryption keys securely. Avoid hardcoding keys in your application to enhance security.

4. Implement Access Control

Ensure that only authenticated and authorized users can upload or download files. Use Role-Based Access Control (RBAC) to manage permissions effectively.

5. Enable HTTPS

Always use HTTPS for file uploads and downloads to encrypt data in transit. This protects your application from man-in-the-middle (MITM) attacks.
Get to know about differences between HTTP and HTTPS here
https://www.keycdn.com/blog/difference-between-http-and-https

6. Log and Monitor Activities

Implement logging for all file operations to track user activities and detect anomalies. Regularly review logs for potential security breaches.
Learn best practices for logging here
https://betterstack.com/community/guides/logging/logging-best-practices/

Step-by-Step Implementation Guide

Step 1: Adding Dependencies in build.gradle

Add the ‘commons-io’ dependency in your build.gradle file to enable Spring Boot and file handling.

implementation 'commons-io:commons-io:2.16.1'

You can find the dependency here
https://mvnrepository.com/artifact/commons-io/commons-io

Step 2: Creating the AES Encryption Utility

To handle encryption and decryption, we’ll create a utility class using AES (Advanced Encryption Standard).

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESUtil {
public static byte[] encrypt(byte[] data, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
public static byte[] decrypt(byte[] encryptedData, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encryptedData);
}
}

In this class:

  • We create two static methods, encrypt() and decrypt(), that handle the core AES encryption and decryption logic.
  • You’ll notice that a secret key is passed in both methods. Ensure your key is at least 128 bits long.

You can learn about AES encryption here
https://www.geeksforgeeks.org/advanced-encryption-standard-aes/

Step 3: Creating the File Service for Encryption and Decryption

Next, we create the FileService that will handle the encryption and saving of files, as well as their decryption when requested.

import com.shishir.fileencryption.utils.AESUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Service
public class FileService {
private final String directory = "E:\\PERSONAL\\file-encryption-spring-boot\\encryptedfiles\\";
private final String encryptionKey = "mysecretkey12345"; // 128 bit key for AES
public String encryptAndSaveFile(MultipartFile file) throws Exception {
// Create a directory to save files
Files.createDirectories(Paths.get(directory));
// Encrypt the file and save
byte[] encryptedData = AESUtil.encrypt(file.getBytes(), encryptionKey);
String filePath = directory + file.getOriginalFilename() + ".enc";
Files.write(Paths.get(filePath), encryptedData);
return filePath;
}
public Path decryptAndRetrieveFile(String fileName) throws Exception {
Path encryptedFilePath = Paths.get(directory + fileName + ".enc");
// Decrypt the file
byte[] decryptedData = AESUtil.decrypt(Files.readAllBytes(encryptedFilePath), encryptionKey);
Path decryptedFilePath = Paths.get(directory + "decrypted_" + fileName);
// Save decrypted file
Files.write(decryptedFilePath, decryptedData);
return decryptedFilePath;
}
}

Step 5: Building the File Controller

Now, we’ll expose two endpoints to:

  • Upload and encrypt files.
  • Decrypt and download files.
import com.shishir.fileencryption.service.FileService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
@RestController
@RequestMapping("/api/files")
public class FileController {
private final FileService fileService;
public FileController(FileService fileService) {
this.fileService = fileService;
}
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
try {
String encryptedFilePath = fileService.encryptAndSaveFile(file);
return "File uploaded and encrypted successfully: " + encryptedFilePath;
} catch (Exception e) {
return "File upload failed: " + e.getMessage();
}
}
@GetMapping("/download")
public String downloadFile(@RequestParam String fileName) {
try {
Path decryptedFilePath = fileService.decryptAndRetrieveFile(fileName);
return "File decrypted successfully: " + decryptedFilePath;
} catch (Exception e) {
return "File download failed: " + e.getMessage();
}
}
}

Conclusion

We covered how to implement file encryption and decryption using Spring Boot and AES encryption. You learned how to:

  • Build a utility for AES encryption and decryption.
  • Create endpoints to upload encrypted files and retrieve decrypted files.

By implementing this approach, you ensure that user files are securely stored and can only be accessed by authorized entities.

Building a secure file upload and download system in Spring Boot requires careful planning and execution. By following the best practices outlined in this guide and implementing the steps provided, you can ensure that your application handles files securely. This not only protects sensitive data but also enhances user trust and compliance with data protection regulations.

If you’d like to see the complete code, you can find it in my GitHub repository:
https://github.com/gitshishirkarki/file-encryption-spring-boot

Happy Coding!

Connect me,

My LinkedIn : Shishir Karki
My Github : Git Shishir Karki

Learn more Build a Secure File Upload and Download System with Encryption in Spring Boot

Leave a Reply