A hybrid approach to encrypt data on client side before sending to backend using both RSA + AES.
- Node.js >=22 installed.
-
Create a
keys
folder in the project root. -
generate RSA key pair -
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private.pem -out public.pem
- Put
public.pem
andprivate.pem
underkeys
.
- Install dependencies
npm i
- Run
npm start
- Visit
http://localhost:5000
- Generate RSA Key pair on server, store these keys securely somewhere.
- Create endpoint to serve RSA public key.
- On submission of data, extract encrypted AES key, iv and form fields from request.
- Use private RSA key to decrypt AES key received from client.
- Use decrypted AES key to decrypt the form data.
- fetch RSA public key on initial load from server.
- When form is submitted, generate a random AES 256-bit key and iv using Web Crypto.
- Encrypt form fields with this key using AES algorithm of choice.
- Before submitting data to backend, encrypt AES key itself using RSA public key fetched from server.
- Send encrypted AES key + form data + iv to backend.
TLS ensures:
-
Data is encrypted in transit (between browser and server).
-
Data can't be intercepted or modified by attackers while in transit.
-
Server authenticity (via certificate verification).
But TLS does not protect against:
-
Malicious or compromised frontend
If an attacker injects malicious JavaScript (via XSS), they can access raw form data before it’s sent via TLS. Rule of thumb is you should never trust client side.
-
Insider threats on backend
Developers, DBAs, or insane people might have access to backend DB, logs, or memory — and can see decrypted data. If you are working with extremely sensitive data you should encrypt it at rest.
If you encrypt sensitive fields at the application level, the backend must explicitly decrypt them, reducing passive exposure.
-
Data breaches
Data at rest on server side will be exposed in the breaches if unencrypted, TLS is not even in the picture here.
-
Zero-trust architecture / secure multi-tenancy
Sometimes backend services are not fully trusted — app-layer encryption helps in such cases. E.g., encrypting one tenant’s data such that no other tenant or service can decrypt it.
-
Legal/compliance requirements
Some industries (finance, healthcare) require field-level encryption, even if data is sent over HTTPS. E.g., HIPAA, PCI-DSS, GDPR recommend/require this for sensitive fields.
Encrypts payloads (e.g. form data) directly using RSA public key.
Pros:
-
Simpler architecture: Just RSA keys, no symmetric key handling.
-
No need for hybrid key exchange logic.
-
Public key can safely live on frontend.
Cons:
-
RSA is slow and not designed for large data encryption: Standard RSA (e.g., 2048-bit) can only encrypt up to ~200–245 bytes at a time (depending on padding). You’d need to split large payloads into chunks and reassemble.
-
Bad for performance on mobile / low-power devices.
-
Payload size increases due to RSA padding (especially with longer keys).
-
If you're encrypting more than just a few small fields, it's a bad fit.
When to use this approach:
- For smaller payloads and low traffic backends RSA is secure and simple.
Encrypt payloads (e.g. form data) using AES key generated on client using web crypto or received from server.
Pros:
- Faster and more efficient than RSA
- No need to split large payloads
Cons:
- Unsafe. If you serve the AES key from server it will be exposed on client side (network tab). If you generate AES key on client side using web crypto, you need to send it to server and it will be exposed on client side (network tab).
When to use this approach:
- backend-to-backend communication where key is never exposed to untrusted clients.
Generate AES key on client to encrypt payloads (e.g. form data), encrypt AES key using RSA public key received from server.
Pros:
-
Efficient and secure:
-
AES is fast and good for large payloads.
-
RSA is only used to encrypt a small AES key (~32 bytes).
-
-
Industry standard approach (used in TLS, PGP, etc.).
-
Enables authenticated encryption (AES-GCM gives you integrity checks).
-
Can encrypt whole payloads (not just fields) with ease.
Cons:
- Complex logic
- Need to generate and transmit an AES key + IV.
- Backend must handle AES decryption before applying business logic.
- Requires secure random generation (usually fine with crypto.getRandomValues()).
Feature | RSA-only | AES-only | Hybrid (AES + RSA) |
---|---|---|---|
Encryption Speed | Slow | Fast | Fast |
Large Data Support | Bad | Good | Good |
Code Simplicity | Simple | Simple | Complex |
Security | Secure | Unsafe | Industry Standard |
Frontend Load | High | Low | Low |
- Client side cannot be trusted.
- RSA (asymmetric encryption) is good for small payloads.
- AES (symmetric encryption) is good for large payloads.
- Symmetric encryption is only safe is the key is never exposed to untrusted clients.
- Asymmetric encryption is safe if the private key is never exposed (there's no need either).