Cryptography & Key Management
Cryptography is easy to call and hard to get right. The algorithms are rarely the weak point. How you handle the keys around them almost always is. Use proven primitives through proven libraries, and focus your attention on where keys live, how they rotate, and who can reach them.
The rule that helps most often is the simplest: do not invent it. Use checked, standard, well-maintained libraries for hashing, encryption, signing, and randomness, and use them in the way they are meant to be used. Then protect keys carefully, because an algorithm is only as strong as the secrecy and lifecycle of its key.
The Finperiti sample is a warning: one shared symmetric (HS256) JWT secret used across all tenants. With a shared symmetric secret, anyone who can verify a token can also forge one, and a single leak compromises everyone. Asymmetric signing and per-scope keys exist to limit that blast radius.
Use proven crypto correctly
- DoUse standard, current algorithms (for example AES-GCM for encryption, SHA-256 or stronger for hashing, asymmetric RS256/ES256 for signing) through maintained platform libraries.
- AlwaysHash passwords with a per-user salt and a memory-hard function (Argon2, bcrypt, or PBKDF2 with strong parameters). Never use a plain or fast hash.
- DoUse a cryptographically secure random source for tokens, salts, and IVs. Never use a general-purpose PRNG.
- ConsiderAsymmetric signing for tokens and webhooks, so verifiers cannot forge, and so a leaked verification key is not also a signing key.
- Do notRoll your own crypto — custom ciphers, custom token schemes, hand-built MACs, or home-made "encryption" using XOR or encoding.
- NeverStore passwords in a form you can recover, or compare or return them in plaintext.
- NeverUse a single shared symmetric secret across tenants or services to sign tokens. A leak, or a malicious verifier, then becomes a forger.
Manage keys like crown jewels
- DoKeep keys in a managed key store or HSM (for example Azure Key Vault), generated and used there where possible, not in code, config, or env files.
- DoSeparate keys by purpose and environment: different keys for dev, test, and prod, for signing versus encryption, and ideally per tenant where that limits the blast radius.
- DoDesign for rotation from day one: versioned keys, overlap windows, and the ability to roll a key without downtime or a code change.
- ConsiderEnvelope encryption (data keys wrapped by a master key in the vault) for encrypting data at rest at scale.
- Do notHard-code, log, or embed keys in client-side code, error messages, or telemetry.
- NeverReuse one key across environments or services, or leave a known-exposed key in place. A leaked key is compromised. Rotate it at once and treat it as a breach.
// appsettings.json, same value in every environment
"Jwt": { "Secret": "super-secret-shared-key" }
Anyone who can validate a token can also forge one, and one leak breaks every tenant. Move to asymmetric keys (private key in the vault) and verify with the public key.
var key = await keyVault.GetKeyAsync("jwt-signing", version);
// sign with the private key in the vault; clients verify with the public key
The signing key never leaves the vault, rotates by version, and a leaked verification key cannot be used to forge.
Self-review checklist
- AskAm I using a standard library the way it is meant to be used, or improvising?
- AskWhere does this key live, and who or what can read it?
- AskIf this key leaked tomorrow, how would I rotate it, and how big is the blast radius?
- AskIs the same key being used across environments, tenants, or purposes?