Generally securing a web app to most devs mean database encryption or HTTPS. But what about files your application stores? Many public-facing web application are built to provide some type of service to clients. This means that you store client information on your application, these maybe minor details like their names, email or even their documents and profile pictures.
Too often, these get dumped in /uploads/ or a public_html subfolder with predictable paths. It's easy to forget that these files can contain sensitive business or personal information, and if your access control fails or server gets misconfigured, they're publicly accessible.
The main focus on this article are those documents and profile pictures, how can we safeguard customer data while still being able to provide access to these pictures, files and documents.
Small but important nuance: encryption mainly protects you when storage itself leaks (backups, disks, buckets). It does not replace proper auth, access control or secure coding.
Would you store sensitive records in a table without encryption or access control? No. So why treat files any differently?
Using a strong symmetric encryption algorithm like AES-256 protects your files even if hackers gained access to your files, as long as they don’t also have your keys and decryption path. Here's my flowchart:
🔥 Pro Tip: Don't hardcode keys, always assume your attacker may even have access to your source code. Use a secure secrets manager (like AWS KMS) or a similar secrets/key management service in your stack, and plan for key rotation.
To a certain extent yes, encrypting and decrypting files always adds a little overhead, especially if you're working with large files or doing it frequently. But for most web applications, this impact is very minimal and really doesn't affect user experience. Personally here are some of the things I consider:
🔑 I've mentioned this during one of my client meetings "Security always has a trade-off. A few milliseconds of processing time is a small price for preventing even the smallest data breaches."
Evidently I can't show you how to implement this in every programming language so I will walk you through the logic and a few code snippets in PHP.
For encrypting files on upload you could be looking at openssl or similar modules in your stack.
A simple (but not production-complete) example using AES-256-GCM might look like this:
$contents = file_get_contents($_FILES['file']['tmp_name']); $encrypted = openssl_encrypt($contents, 'AES-256-GCM', $key, OPENSSL_RAW_DATA, $iv, $tag); file_put_contents('/secure/path/file.enc', $iv . $tag . $encrypted);🔥 Pro Tip: Now depending on your stack it may only have AES-256-CBC. In this case you could combine it with a separate HMAC (Encrypt-then-MAC) so that you can detect tampering. Always use a fresh random IV for each file.
Make sure storage directory is not accessible via public URL. Use:
Storage::disk('private') or similar approach in your stackIt's a great first step, but it doesn't prevent leaks, Consider this S3's private ACL blocks direct access, but if someone leaks a signed URL, that file's available until expiry. You still need backend-level permission checks before generating URL.
So encrypting sensitive files even before they go to S3 is a smarter approach, that way even if the bucket is compromised, files are useless without the key.
Instead of letting the browser hit /uploads/invoice.pdf, you:
Yes, but don't rely on this alone if a file is public and sensitive, you lose control as soon as it's cached or shared. Serving files directly from a public path (like /uploads/invoice.pdf) assumes that:
Use backend endpoints like /api/download/{id}, validate session/JWT there, decrypt, and stream file securely.
Even filenames like johndoe-CTscan-2023.pdf can leak sensitive info. So use a UUID or hash for saved files:
$randomName = bin2hex(random_bytes(16)) . '.enc';Then you could either dynamically generate a name during stream download or map the original name and file type in your database.
So you see it's not an over complex process and implementing this type of encryption not only keeps your end users safe but also proves your skills as a security-focused developer. Just make sure you pick modern modes (like AES-GCM or AES + HMAC), manage keys properly, and remember that encryption complements—rather than replaces—good access control.
If you liked this article checkout other articles in this series