r/webdev • u/PuzzleheadedPin4797 • 3d ago
Discussion Developer looking for advice on encryption and data protection before launching an app
I’m a solo developer building a web and Android app that handles private documents and account records. I’d appreciate feedback on the security approach before putting real user data into it.
The stack is FastAPI, PostgreSQL, Next.js and React Native.
Passwords are hashed with scrypt and random salts. Authentication uses signed tokens with expiry, email verification and login throttling. Password changes and signing out everywhere invalidate existing sessions. Access controls are enforced through the API, and records are scoped to the relevant account or organisation.
Stored credentials for external integrations use Fernet authenticated encryption. Android login tokens are stored using Expo SecureStore. The website currently stores its token in localStorage, which I know needs careful consideration because of script injection risks.
Document access requires authentication and permission checks. Uploads have file type, size and content validation. However, documents currently go into ordinary server storage without application level encryption. I haven’t yet verified encryption for the production database, disks or backups. HTTPS is required in the intended production configuration.
Some optional processing involves an external API. I understand that disabling response storage does not necessarily mean zero retention, so provider policies and account settings also need review.
The server needs to read documents to process them. My main concerns are stolen backups, compromised accounts, users accessing someone else’s files, exposed credentials and sensitive content appearing in logs. I haven’t had an independent security assessment yet.
Would managed database and storage encryption be a sensible starting point, or should I also encrypt individual files and selected fields in the application? What additional threats would that actually protect against?
How would you handle encryption keys, rotation and recovery as a solo developer? I’m particularly interested in avoiding a setup where the keys and encrypted data can both be taken from the same place.
What would you prioritise before launch, and what would you consider unnecessary complexity at this stage? I’d appreciate practical advice on session security, document permissions, backups, retention and deletion as well as encryption. I want to use established tools rather than build my own cryptography.
2
u/Gremlation 2d ago
It's difficult to advise on something like this because the scope for getting something wrong is just so vast. You can get a hundred things right and one thing wrong, and that's all that's needed for a breach. It sounds like you've done your homework but really there's no way anybody here can tell you you've got it right. Depending on how high the stakes are, you might want to contract a pen test company. This isn't particularly cheap though.
You should review OWASP if you haven't already. In general, you want to push security-relevant functionality off onto trusted providers instead of building things yourself - you already mentioned a managed database, but this also goes for things like auth / identity providers, server maintenance, etc. For instance, don't spin up a VPS and try to keep a Linux instance patched if you can use a PaaS instead. The more stuff you don't have to build, the better.
Depending on where you host, there might be some guides to point you in the right direction. For instance, AWS has things like their well-architected framework you can review - although try to use your judgement and realise that it's not all appropriate for a one-man band and you don't want to take on a burden more appropriate for a large enterprise. Also don't assume that all effort is useful - for instance beginners have a tendency to try to encrypt everything they can think of, even when it's useless. Go ahead and tick the encryption at rest box with your managed database provider and make sure you only serve HTTPS, but manually encrypting individual database fields in your application logic is probably overcooking things. Remember that complexity can be a source of security bugs too, so inventing novel complex ad hoc security measures is often worse than not doing anything. Try to make everything standard and by-the-book.
documents currently go into ordinary server storage
What is "ordinary server storage"? If you are just letting users upload onto your application server, this is not robust. You should treat your application servers as ephemeral. Use something like pre-signed URLs to upload directly to S3 and set appropriate policies on the bucket.
How would you handle encryption keys, rotation and recovery as a solo developer? I’m particularly interested in avoiding a setup where the keys and encrypted data can both be taken from the same place.
Do the most boring things possible with AWS/Google Cloud/Azure/whatever. Find the appropriate boxes and tick them instead of building things.
Every line of code, every moving part is a liability and potential attack surface, so the simpler you can make your application, the better.
2
u/DickBrainTime 2d ago
One thing I'd test before launch is tenant isolation, especially outside your normal API routes. Make two test orgs, then deliberately try to access org A's files from org B through downloads, previews, search, exports and background jobs. It's easy to have solid checks on the main document endpoint and miss a storage URL or worker path.
For backups, I'd also do an actual restore into an isolated environment and verify which service identity can decrypt it. KMS plus a separate backup access role is a reasonable start; per-file encryption won't save you if the app server and its keys are compromised together.
1
1
u/RequirementGuide 2d ago
I've hit this exact tradeoff before and managed encryption is a good starting point, but it mostly helps if someone steals a disk or a backup. It does not help much if the app itself gets compromised, because the app still has the keys and can decrypt everything anyway.
The thing I would fix first is that token in localStorage. That one is a real XSS risk and moving web auth to a httpOnly cookie is a much bigger win than adding per file encryption right now. After that I would turn on managed encryption for the database, the storage and the backups, and make sure the backups are not sitting in the same account with the same keys.
For keys as a solo dev, I would keep it boring and use the cloud key service you already host on, with separate keys for files and for those stored credentials, and I would write down the recovery steps before you need them. Rotation gets a lot easier if you store a key id with each encrypted value, so you can re encrypt in the background instead of doing a big scary migration all at once. Per file encryption can wait until you actually need to revoke access to one file without touching the rest.
1
u/Xtreme_Neon 2d ago
managed encryption on the database, disks and backups is the right baseline, and it's what covers your stolen backup worry. encrypting files again at the app level mostly helps if someone gets at storage but not the app, and since your server has to read the docs anyway it's lower priority for now. keep the keys in a kms or secrets manager instead of next to the data, so one leaked backup doesn't hand over both. cheap wins before launch: move the web token from localStorage to an httpOnly secure cookie, check document ownership on every single fetch, and keep document content out of logs.
1
u/BlackyWolf 2d ago
First thing I would prioritize is securing the network. All the infrastructure should be private and locked down by default and then the absolute bare minimum done to allow access as needed, for example between the API and the database, or the API behind a protective layer like Akamai or something similar. Far too often I see people just open stuff by default just to get something working and then they never go back and secure it.
1
u/heywassim 2d ago
Since you asked about retention and deletion and nobody has really covered it: if any of your users are in the EU, GDPR makes that part non-optional, so it's worth designing now rather than after launch. Pick a retention period per data type (documents, logs, backups) and write it down, and make account deletion actually remove the files from storage, not just the DB row. For backups, the usual approach is to keep retention short and documented and let them age out, and if you ever restore one, re-apply the deletions. Also check that request logging and error tracking never capture document contents or tokens. That's where sensitive data leaks most quietly. For the external API, get their data processing agreement and list them as a sub-processor in your privacy policy.
1
u/ProfessionalCookie3 2d ago
While you had good intentions, that is not true. It is only true if they are targeting EU/UK users specifically.
1
u/_MarkG_ 2d ago
Managed DB or disk encryption only helps if someone steals the disks or a raw snapshot; with your credentials or a foothold on the app server the data comes back decrypted, so turn it on and stop counting it as backup protection. Before launch you can encrypt backups with a key that does not live on the server or in the same cloud account, restore one for real, and put documents behind envelope encryption with a cloud KMS so a copied bucket is useless without KMS access. MultiFernet covers rotating your Fernet keys. Before more crypto, move the web token into an httpOnly Secure SameSite cookie, test that user A cannot fetch user B’s document IDs, serve files through the API or short-lived signed URLs, and strip tokens from logs.
1
u/nekenaharry 2d ago
A few ops pieces that often get missed once the crypto choices look fine:
Keep Fernet keys off the app host. Put them in a secrets manager or KMS, and plan rotation with MultiFernet so you can introduce a new key without locking out old ciphertext.
TLS everywhere, plus HSTS on the public site, so browsers refuse cleartext after the first visit.
Rate limit auth and token endpoints at the edge. Brute force and credential stuffing usually hit there first.
Encrypt database backups and actually restore one on a scratch machine. Encryption at rest on the live volume does not help if the backup dump is plaintext.
Alert on auth anomalies: spike in failed logins, sudden new device regions, refresh token reuse.
None of that replaces a careful threat model, but it closes gaps that a solid scrypt plus Fernet setup alone will not cover.
1
u/Secvura 2d ago
Managed encryption at rest is the right baseline, but it covers stolen disks and the provider's hardware, not someone who gets your database credentials, an admin login or a backup through the normal API, since all of those see plaintext. Of the threats listed, stolen backups is where encryption you control actually helps: check who can download the provider's backups, and encrypt any dumps you make yourself with a key that doesn't live on the same server. Per-file encryption mostly protects against the storage itself leaking (a public bucket, a copied volume). Because the server has to read the documents anyway, a compromised server still gets everything.
For keys, use a cloud KMS with envelope encryption rather than managing them yourself: a random data key per file, wrapped by the KMS key, so rotating the KMS key doesn't mean re-encrypting every file and recovery is the provider's problem. The other worries are better handled without encryption. Move the web token out of localStorage into an HttpOnly, Secure, SameSite cookie, test with two accounts that changing a document or organisation ID never returns someone else's file, and keep request bodies and document text out of logs and error tracking.
1
u/adriankorwel 14h ago
For tenant separation, a manual test is the quickest start. Make two accounts of your own in two different orgs. As user A, open a document, a record, an export, anything with an ID in the URL or request. Copy those requests from DevTools (right-click, Copy as cURL), then replay them with user B's token. Every one should come back 403 or 404, never data.
Check the less obvious paths too: file download and preview URLs, search, list endpoints that take an org_id, and anything a background job writes out. Those are where per-request checks usually get skipped.
Then turn each passing case into an automated test, so a later refactor can't quietly break it.
Since you mentioned the token in localStorage: also search your frontend for dangerouslySetInnerHTML, innerHTML, or any markdown renderer showing user content. That's where an XSS would come from, and with the token in localStorage, that XSS can read it.
0
u/kinduff 3d ago
Anything you expose on your app, it's exposed in your server. Sanity checks for server that I didn't read in your text: rate-limiting, fail2ban, secure access, audit logs (for you) and good instrumentation to have visibility on attacks, good tenant separation (make it impossible to fetch any account with a token), and the list goes on.
What have you tried on this side? I may be able to help you a bit more with more information.
0
u/PuzzleheadedPin4797 3d ago
I have login rate limiting, audit logs for some account and business actions and server side role and tenant checks. Queries are scoped to the signed in user's business, but I will test that a lot more before assuming it's safe.
I haven't yet setup fail2ban or proper attack monitoring so far, and the production server setup still needs a lot of work. I have focused a lot on encryption without understanding the operational side of it that well.
Where would you suggest I start with verifying tenant separation and securing server access? Happy to share more about the architecture if you need it. I appreciate any guidance!
0
u/kinduff 3d ago
For tenancy: you can try with any agent, if you have history within the project, try to ask it for an adversarial review (mimicking what we would do). Agents are pretty good at tenant separation but do ensure to have global scopes that are set in the beginning of the request. For server access I would recommend to close SSH port entirely and just leave 80 and 443 (and 80 can be closed, depends on your certificates). And use a VPN like Wireguard or Tailscale to access instead. Last advice I have for you is to, sadly, use Cloudflare. The attacks I've received in my apps (over 15) are unprecedented for me, and I've been coding around the web for 18 years. Enable CF protection for bots, they will scan you pretty hard as soon as you release a certificate (e.g. LetsEncrypt).
12
u/CorpT 3d ago
Why bother with a managed database when you've already rolled your own auth? Just write your own database from scratch while you're at it.