The goal
Learn to choose the right security control for the problem, explain why it works, implement the safe default in Java, and identify where it belongs in a distributed system. This is a learning guide, not a substitute for a security review or your organization’s cryptographic policy.
Start with the security question, not the algorithm
- Confidentiality: Can an unauthorized person read it?
- Integrity: Can someone change it without detection?
- Authenticity: Can I verify who sent it?
- Authorization: Is this identity allowed to do this action on this resource?
- Availability: Can the system continue to serve legitimate users?
- Accountability: Can we investigate what happened without leaking secrets?
1. The map: security across system-design layers
flowchart TB U[User / Client] --> EDGE[DNS, CDN, WAF, DDoS controls] EDGE --> TLS[TLS termination / certificate validation] TLS --> API[API Gateway / REST endpoint] API --> ID[Authentication: session, OAuth2/OIDC, JWT] ID --> AUTHZ[Authorization: roles, scopes, ownership, policy] AUTHZ --> APP[Application: validation, safe coding, rate limits] APP --> DATA[Database: least privilege, encryption at rest] APP --> MQ[Kafka: TLS, SASL, ACLs, quotas] APP --> OBJ[Object storage: IAM, encryption, access policy] APP --> SECRETS[Secrets manager / KMS / HSM] DATA --> OBS[Audit logs, metrics, alerts] MQ --> OBS APP --> OBS
A secure architecture is layered. TLS cannot fix broken authorization. Encryption at rest cannot stop a compromised application that is allowed to read all rows. A strong password hash cannot stop credential phishing. Each control protects against a specific class of failure.
1.1 Threat modeling: what are we protecting, from whom, and how?
Use STRIDE as a first-pass checklist:
| Threat | Meaning | Example | Typical controls |
|---|---|---|---|
| Spoofing | Pretending to be another identity | Stolen session token | MFA, short-lived credentials, TLS, token validation |
| Tampering | Unauthorized modification | Change order total in request | Server-side validation, authorization, integrity controls |
| Repudiation | Denying an action | Admin denies deleting account | Protected audit logs, identity, timestamps |
| Information disclosure | Reading data without permission | IDOR leaks another user’s invoice | Object-level authorization, minimization, encryption |
| Denial of service | Making service unavailable | Login brute force or request flood | Rate limits, quotas, DDoS protection, backpressure |
| Elevation of privilege | Gaining greater permissions | User calls admin endpoint | Least privilege, policy checks, secure defaults |
Head First prompt
Imagine you have a bank transfer endpoint. Ask: who can call it, how do we know the caller, how do we prove the amount was not changed, how do we prevent a user changing someone else’s account ID, and how do we investigate abuse? Those are separate design questions.
2. Cryptography: the four tools that people confuse
flowchart TD C[Cryptographic goal] --> H[Hash / digest] C --> M[MAC / HMAC] C --> E[Encryption] C --> S[Digital signature] H --> H1[Detect accidental or malicious change only when digest is trusted] M --> M1[Integrity + authenticity for parties sharing a secret key] E --> E1[Confidentiality; AEAD also protects integrity] S --> S1[Integrity + origin authentication with public-key verification]
- Hash: one-way fingerprint of bytes. No secret key.
- MAC/HMAC: keyed integrity check. Both producer and verifier know the secret.
- Encryption: reversible with the right key; primarily confidentiality.
- Digital signature: private key signs; public key verifies. Does not hide the content.
A checksum is not automatically security. If an attacker can change both a file and its adjacent SHA-256 checksum, the attacker can replace both. For security, the expected digest must come from a trusted channel, or use a MAC/signature.
3. Hashes: MD5, SHA-1, SHA-2, SHA-3
3.1 What is a hash?
A cryptographic hash function maps input of arbitrary length to a fixed-size digest:
digest = H(message)
Think of a tamper-evident fingerprint. The same bytes should produce the same digest, but the original message should not be feasibly recoverable from the digest.
Desired properties:
- Preimage resistance: given
h, infeasible to findmsuch thatH(m) = h. - Second-preimage resistance: given
m1, infeasible to find a differentm2with the same digest. - Collision resistance: infeasible to find any two different inputs with the same digest.
- Avalanche effect: a tiny input change radically changes the output.
No hash can be mathematically collision-free because an unlimited input space maps to a finite output space. Security means finding a useful collision is computationally infeasible.
3.2 A short history and what changed
- MD5 (1992): 128-bit digest; designed for fast integrity checks. Practical collision attacks make it unsuitable where an attacker could exploit collisions. Do not use for signatures, certificates, or security-sensitive integrity.
- SHA-1 (1995): 160-bit digest; collision attacks have made it unsuitable for new collision-resistant security uses.
- SHA-2 (standardized in 2001): includes SHA-256 and SHA-512. SHA-256 is a common general-purpose choice.
- SHA-3 (standardized in 2015): a different internal design (Keccak-based), offering an alternative construction; it is not simply “SHA-2 but newer.”
| Algorithm | Output | Use today |
|---|---|---|
| MD5 | 128 bits | Legacy/non-security checks only; avoid for adversarial integrity |
| SHA-1 | 160 bits | Legacy interoperability only; avoid new security use |
| SHA-256 | 256 bits | General-purpose digest, content fingerprints, signatures/HMAC constructions |
| SHA-512 | 512 bits | General-purpose digest where appropriate |
| SHA-3-256 | 256 bits | Alternative modern digest construction |
Hashing is not encryption
A hash has no decryption key. Do not promise that a hash “encrypts” data. And do not store passwords as
SHA256(password): it is too fast for password guessing.
3.3 Java: compute a SHA-256 digest
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
public final class Digests {
public static String sha256(String value) throws NoSuchAlgorithmException {
byte[] digest = MessageDigest.getInstance("SHA-256")
.digest(value.getBytes(StandardCharsets.UTF_8));
return HexFormat.of().formatHex(digest);
}
}Use MessageDigest for a digest, not for password storage. In Java, MessageDigest instances are mutable and should not be shared concurrently without proper synchronization or per-operation instances.
Good uses: comparing a downloaded artifact against a trusted published digest; content-addressed storage; building blocks inside a vetted signature/HMAC protocol.
Bad uses: password storage; homemade authentication tokens; treating an untrusted checksum as proof of authenticity.
3.4 MD5 in legacy systems
You may encounter MessageDigest.getInstance("MD5"). Being available in a JDK does not make it safe. For a migration:
- identify what the digest protects;
- determine whether attackers can choose or modify inputs;
- replace it with SHA-256 or a vetted MAC/signature design where appropriate;
- plan compatibility and re-computation;
- test old/new formats and document the cutover.
Do not mechanically replace every MD5 use without understanding the protocol. Some non-security identifiers/checksums may have compatibility requirements.
4. HMAC: a hash plus a secret key
A plain hash cannot tell you who created it. HMAC uses a secret key with a hash function:
tag = HMAC(secretKey, message)
Only parties with the shared key should be able to produce a valid tag. HMAC is commonly used in API request signing and internal integrity protocols.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
public final class HmacExample {
public static String hmacSha256(byte[] secret, String message) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret, "HmacSHA256"));
return HexFormat.of().formatHex(
mac.doFinal(message.getBytes(StandardCharsets.UTF_8)));
}
}Don't invent a signing protocol casually
A real request-signing scheme must define canonicalization (method, path, query, body digest, timestamp, nonce), replay prevention, key rotation, and constant-time tag comparison. Prefer a standard protocol or mature library. Never compare secret-derived tags with a naive early-exit loop if timing leakage matters.
5. Passwords: password encoder, salt, pepper, and work factor
5.1 Why SHA-256 is wrong for passwords
A password is a low-entropy human guess, not a random 256-bit key. An attacker who steals a database can try likely passwords offline. Fast hashing lets them test huge numbers of guesses per second.
Password storage needs a password hashing / key derivation function designed to make each guess expensive:
- Argon2id: preferred modern choice where supported; memory-hard.
- scrypt: memory-hard alternative.
- bcrypt: widely deployed adaptive function; note its input-length limitations.
- PBKDF2-HMAC-SHA-256: useful where compliance or platform constraints require it.
Each password gets a unique random salt. The salt is stored alongside the resulting hash and is not a secret. It defeats precomputed rainbow tables and ensures equal passwords do not normally yield equal stored hashes.
A pepper is an additional secret held separately (for example, in a secrets manager/HSM), not in the user database. It can add defense in depth but creates operational complexity and a rotation/recovery problem.
5.2 Registration and login
sequenceDiagram participant U as User participant A as Application participant P as Password encoder participant DB as User database U->>A: Register password A->>P: encode(password) P->>P: Generate unique salt + expensive KDF P-->>A: Encoded value (algorithm + params + salt + hash) A->>DB: Store encoded value U->>A: Login password A->>DB: Load encoded value DB-->>A: Stored encoded value A->>P: matches(candidate, stored) P-->>A: true / false A-->>U: Establish session/token only if valid
Store a self-describing encoded string where the library supports it. It should carry algorithm/version and cost parameters so you can increase work factors and rehash after a successful login.
5.3 Spring Security example
With Spring Security, use its PasswordEncoder abstraction and a supported adaptive encoder. For example, Argon2PasswordEncoder requires an appropriate provider/dependency; verify current Spring Security guidance and tune parameters against your production latency and capacity budget.
// Conceptual Spring Security usage; configure the chosen encoder
// and parameters according to current framework guidance.
PasswordEncoder encoder = /* configured Argon2PasswordEncoder or DelegatingPasswordEncoder */;
String stored = encoder.encode(rawPassword); // registration/reset
boolean valid = encoder.matches(candidatePassword, stored); // loginNever implement password hashing yourself. Do not log raw passwords, put them in analytics, or return them in API responses. Use rate limits, MFA/passkeys where appropriate, secure reset flows, breached-password checks where available, and generic login error messages that reduce account enumeration.
Interview answer
“I store an adaptive password hash, not encrypted or plain passwords. I use a unique salt and a supported encoder such as Argon2id, tune its cost to the environment, and rehash after successful login when parameters become outdated. I add rate limiting and MFA because password hashing alone doesn’t stop phishing or online guessing.”
6. Symmetric encryption: AES and authenticated encryption
Symmetric encryption uses the same secret key to encrypt and decrypt. It is efficient for large amounts of data, which makes it the normal choice for bulk encryption.
- AES: widely used block cipher with 128-bit blocks and 128/192/256-bit keys.
- Mode matters: the cipher alone does not define a safe scheme.
- Prefer AEAD: authenticated encryption with associated data, such as AES-GCM or ChaCha20-Poly1305. It provides confidentiality plus integrity/authenticity of ciphertext.
- Nonce/IV: must follow the algorithm’s uniqueness/randomness requirements. For AES-GCM, nonce reuse with the same key can be catastrophic.
- AAD: additional authenticated data is authenticated but not encrypted, e.g. a record ID or format version.
flowchart LR P[Plaintext] --> ENC[AEAD encrypt with key + unique nonce + optional AAD] K[Secret key] --> ENC N[Nonce] --> ENC AAD[Associated data] --> ENC ENC --> OUT[Ciphertext + authentication tag] OUT --> DEC[AEAD decrypt and verify] K2[Same secret key] --> DEC N2[Nonce] --> DEC AAD2[Same AAD] --> DEC DEC -->|Valid tag| P2[Plaintext] DEC -->|Invalid tag| FAIL[Reject; do not use partial plaintext]
Avoid ECB. Avoid designing new CBC encryption without a sound authentication construction. Do not reuse nonces with AES-GCM under the same key. Prefer platform KMS/envelope encryption rather than inventing a key-storage system.
Java AES-GCM example
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.security.SecureRandom;
import java.util.Arrays;
public final class AesGcmExample {
private static final int NONCE_BYTES = 12;
private static final int TAG_BITS = 128;
private static final SecureRandom RNG = new SecureRandom();
public record Sealed(byte[] nonce, byte[] ciphertextAndTag) {}
public static SecretKey newKey() throws Exception {
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256);
return generator.generateKey();
}
public static Sealed encrypt(SecretKey key, byte[] plaintext) throws Exception {
byte[] nonce = new byte[NONCE_BYTES];
RNG.nextBytes(nonce); // ensure nonce uniqueness for this key
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(TAG_BITS, nonce));
return new Sealed(nonce, cipher.doFinal(plaintext));
}
public static byte[] decrypt(SecretKey key, Sealed sealed) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key,
new GCMParameterSpec(TAG_BITS, sealed.nonce()));
return cipher.doFinal(sealed.ciphertextAndTag()); // fails if tag invalid
}
}This is a teaching example, not a complete production storage format. Production code must define serialization/versioning, key IDs, nonce policy at scale, error handling, rotation, access control, and KMS integration. SecureRandom is appropriate for nonce generation, but random generation alone does not excuse nonce reuse.
7. Asymmetric cryptography: RSA, public keys, private keys
RSA uses a mathematically related public/private key pair. The public key can be distributed; the private key must remain protected.
Use cases:
- Encryption/key transport: a sender can encrypt a small secret to the recipient’s public key; the recipient decrypts with the private key. For modern designs, use RSA-OAEP where RSA encryption is needed, and generally prefer hybrid protocols rather than encrypting large files directly.
- Digital signatures: the private key signs; the public key verifies. Prefer RSA-PSS for new RSA signatures where supported.
- Not the same operation: signing is not “encrypting with the private key.” Signatures have their own encoding and security properties.
RSA relies on the practical difficulty of factoring a large composite number. Historically, Rivest, Shamir, and Adleman published RSA in 1977. Use approved key sizes and padding; 2048-bit RSA is a common baseline, while 3072-bit RSA is often discussed for longer-term classical security. Follow current organizational policy and threat horizon.
Why not encrypt every payload with RSA?
Public-key operations are slower and RSA can only handle small inputs relative to key size and padding overhead. Real systems use hybrid encryption:
- generate a random symmetric data key;
- encrypt the data with an AEAD cipher such as AES-GCM;
- protect/wrap the data key using a recipient public key or KMS key;
- store the ciphertext, nonce, tag, wrapped key, and key identifier.
Java RSA signature example
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
public final class RsaSignatureExample {
public static void main(String[] args) throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(3072);
KeyPair pair = generator.generateKeyPair();
byte[] message = "approve order 123".getBytes(StandardCharsets.UTF_8);
Signature signer = Signature.getInstance("RSASSA-PSS");
signer.setParameter(new java.security.spec.PSSParameterSpec(
"SHA-256", "MGF1", java.security.spec.MGF1ParameterSpec.SHA256,
32, 1));
signer.initSign(pair.getPrivate());
signer.update(message);
byte[] signature = signer.sign();
Signature verifier = Signature.getInstance("RSASSA-PSS");
verifier.setParameter(new java.security.spec.PSSParameterSpec(
"SHA-256", "MGF1", java.security.spec.MGF1ParameterSpec.SHA256,
32, 1));
verifier.initVerify(pair.getPublic());
verifier.update(message);
boolean valid = verifier.verify(signature);
System.out.println("Signature: " + Base64.getEncoder().encodeToString(signature));
System.out.println("Valid: " + valid);
}
}The verifier must obtain the expected public key through a trusted mechanism. If an attacker can replace both message and public key, signature verification alone doesn’t establish trusted identity.
8. Public Key Infrastructure (PKI), certificates, and trust
A public key does not identify its owner by itself. PKI binds an identity (e.g. a DNS name) to a public key through a certificate signed by a trusted Certificate Authority (CA).
flowchart TD CA[Root CA trust anchor] --> ICA[Intermediate CA certificate] ICA --> CERT[Server certificate: DNS name + public key + validity] CLIENT[Client trust store] --> ROOT[Trusted root certificate] ROOT --> VERIFY[Validate chain, signature, dates, usage, name] CERT --> VERIFY VERIFY -->|Valid| CONNECT[Continue secure connection] VERIFY -->|Invalid| DENY[Fail closed / reject connection]
Certificate validation commonly checks:
- chain to a trusted root;
- signatures and validity dates;
- hostname/SAN matches the requested server;
- key usage and extended key usage;
- constraints and revocation/status policy where applicable.
Certificate ≠ private key. A certificate is normally public; the private key is secret. A certificate expiry or hostname mismatch should not be “fixed” by disabling validation.
Java uses keystores/truststores and JSSE. KeyStore can hold keys/certificates; TrustManager logic validates peer certificates; SSLContext configures TLS. Prefer PKCS#12 for portable key-store files unless the platform has a different managed key store.
9. TLS, HTTPS, and encryption in transit
SSL is the historical predecessor; SSL 2/3 are obsolete. Modern systems should use TLS, typically TLS 1.2 or TLS 1.3 according to policy. HTTPS is HTTP carried over TLS.
TLS provides:
- confidentiality against network eavesdropping;
- integrity against undetected network tampering;
- server authentication through certificates;
- optional client authentication with mutual TLS (mTLS).
Simplified TLS handshake
sequenceDiagram participant C as Client participant S as Server C->>S: ClientHello (supported versions, cipher suites, key share) S->>C: ServerHello (selected parameters, key share) S->>C: Certificate + proof of private-key possession C->>C: Validate certificate chain and hostname C->>S: Finished (handshake integrity proof) S->>C: Finished C<<->>S: Encrypted application data
TLS 1.3’s exact handshake differs from TLS 1.2 and this diagram is intentionally simplified. Modern TLS commonly uses ephemeral key agreement (such as ECDHE/X25519) to derive symmetric traffic keys. RSA certificates may authenticate the server, but RSA key transport is not how TLS 1.3 establishes traffic keys.
TLS termination: a load balancer or gateway may decrypt client traffic. The next hop needs its own security decision. If gateway-to-service traffic crosses an untrusted network or policy requires it, use TLS/mTLS internally too.
Java HTTPS client
Use a modern HTTP client with normal certificate and hostname validation. Do not install a trust manager that trusts every certificate. Do not disable endpoint identification to “make it work.” For internal services, issue certificates from a managed internal CA and rotate them automatically.
10. Encryption at rest, in transit, and in use
| State | Example | Controls | Important limitation |
|---|---|---|---|
| In transit | Browser to API; service to Kafka | TLS/mTLS, certificate validation | Data may be exposed at TLS termination |
| At rest | Database disk, snapshots, object storage | Disk/database encryption, KMS, envelope encryption | Authorized compromised application may still read plaintext |
| In use | Application processes a decrypted record | Isolation, least privilege, memory hygiene, restricted access | Traditional encryption usually needs plaintext during processing |
Envelope encryption
flowchart LR DATA[Plain data] --> DEK[Encrypt with Data Encryption Key / DEK] DEK --> CIPH[Ciphertext] DEK --> WRAP[Key Management Service wraps DEK with KEK] WRAP --> WDEK[Wrapped DEK] CIPH --> STORE[Store ciphertext + wrapped DEK + key ID] WDEK --> STORE STORE --> READ[Authorized reader] READ --> KMS[KMS unwraps DEK under policy] KMS --> DECRYPT[Decrypt data]
- DEK: data encryption key; encrypts the data.
- KEK/KMS key: protects the DEK.
- KMS/HSM: controls key access, audit, rotation and cryptographic operations.
- Rotation: distinguish rotating a wrapping key from re-encrypting all data. The design determines what must be rewritten.
Encryption is only one control. Also use database permissions, tenant isolation, backups protection, deletion/retention policies, key-access audit, and restricted exports.
11. Authentication, authorization, sessions, JWT, OAuth 2.0 and OIDC
- Authentication (AuthN): who are you?
- Authorization (AuthZ): what are you allowed to do?
- OAuth 2.0: delegated authorization framework.
- OpenID Connect (OIDC): identity layer built on OAuth 2.0.
- JWT: token format; a JWT can be signed/MACed, and some JWTs can be encrypted. A typical signed JWT is encoded, not secret.
- Session cookie: opaque identifier referencing server-side session state.
A JWT’s signature protects integrity, not confidentiality. Anyone holding a normal signed JWT can usually decode its header and payload. Never put passwords, private data, or secrets in a plain signed JWT.
JWT validation must include an explicit allowed algorithm policy, signature verification, issuer (iss), audience (aud), expiry (exp), not-before (nbf) if used, and relevant scopes/claims. Do not trust token-supplied key URLs or algorithm choices blindly. Plan revocation, short lifetimes, key rotation, and storage against XSS/CSRF risks.
REST request security flow
sequenceDiagram participant C as Client participant G as API Gateway participant A as API participant P as Policy / Data layer C->>G: HTTPS request + credential G->>G: TLS, rate limit, token validation (where configured) G->>A: Forward trusted identity context A->>A: Validate input and business rules A->>P: Check role/scope AND resource ownership P-->>A: Permit / deny A-->>C: Minimal response, no secrets in errors
Authorization must happen at the resource/action level. Checking that a user is logged in is not enough. For example, /orders/123 must verify that the caller can access order 123; changing the ID must not expose another user’s order (IDOR/BOLA).
12. REST/API security checklist
- Enforce HTTPS; use secure TLS settings.
- Authenticate using an appropriate mechanism (OIDC/OAuth, sessions, workload identity, etc.).
- Authorize every sensitive action and resource; default deny.
- Validate input with allowlists and business constraints; use parameterized SQL.
- Apply request/body size limits, rate limits, quotas, and timeouts.
- Use safe CORS policy; CORS is not authentication.
- Protect browser cookie sessions with
Secure,HttpOnly, appropriateSameSite, and CSRF defenses where needed. - Avoid secrets/PII in URLs, logs, traces, analytics, and error messages.
- Use idempotency keys for retryable financial/side-effecting operations where appropriate.
- Keep dependencies patched; scan software composition, SAST, secrets, and container images.
- Return safe errors; log security-relevant events without logging credentials.
- Protect against SSRF, injection, mass assignment, BOLA/IDOR, deserialization abuse, and request smuggling where relevant.
CORS is not access control
CORS is a browser-enforced cross-origin policy. It does not stop curl, a backend service, or an attacker from making a direct HTTP request. The server must authenticate and authorize requests independently.
13. Java application security layers
Java security building blocks
| Need | Java API / ecosystem |
|---|---|
| Digest | MessageDigest |
| MAC | Mac |
| Encryption | Cipher, GCMParameterSpec |
| Digital signatures | Signature |
| Key generation | KeyGenerator, KeyPairGenerator |
| Key/certificate storage | KeyStore, CertificateFactory |
| TLS | JSSE: SSLContext, TrustManagerFactory, KeyManagerFactory |
| Secure random | SecureRandom |
| Passwords | Spring Security PasswordEncoder or equivalent vetted library |
| Authorization | Spring Security method/request security; application policy checks |
Security implementation rules:
- use standard JCA/JCE APIs and vetted libraries;
- select algorithms and parameters explicitly according to policy;
- use
SecureRandomfor cryptographic randomness; - never hardcode keys or commit secrets;
- store secrets in a managed secrets service or protected keystore;
- avoid custom crypto and custom token formats;
- avoid weak algorithms and obsolete protocols;
- handle failures closed; do not silently bypass certificate checks;
- keep libraries and JDK patched.
Java secure coding reminders
- SQL: prepared statements / parameterized ORM queries.
- Deserialization: avoid deserializing untrusted native Java object streams; use constrained data formats and validation.
- Files: normalize paths, enforce allowed directories, avoid path traversal, limit upload size, scan untrusted uploads.
- Logs: sanitize untrusted data to prevent log injection; redact tokens and sensitive fields.
- Errors: don’t expose stack traces, SQL, internal hostnames, or secrets to clients.
- Concurrency: protect authorization checks and state changes from race conditions; use transactions and correct isolation for business invariants.
14. Kafka security
Kafka is not secure just because it is inside a private VPC. Treat brokers, clients, Connect, Schema Registry, admin tools, and inter-broker communication as separate trust boundaries.
| Control | What it does |
|---|---|
| TLS | Encrypts traffic and validates peer identity; mTLS can authenticate clients with certificates |
| SASL/SCRAM | Authenticates clients with username/password-derived credentials |
| SASL/OAUTHBEARER | Token-based client authentication when correctly configured |
| ACLs / authorizer | Controls which principal may read/write/create topic or access consumer groups |
| Quotas | Limits resource usage per client/principal |
| Encryption at rest | Protects broker disks/snapshots; not a replacement for TLS or ACLs |
| Secret rotation | Reduces impact of compromised credentials |
Kafka security model
flowchart LR PROD[Producer identity] --> AUTH[Broker authentication] CONS[Consumer identity] --> AUTH AUTH --> ACL[Authorization: topic + group + cluster operations] ACL --> TOPIC[Topic access] PROD -. TLS encrypted .-> AUTH CONS -. TLS encrypted .-> AUTH BROKERS[Inter-broker traffic] -. TLS / auth .-> AUTH TOPIC --> DATA[Broker disk encryption + backups] AUDIT[Broker/client logs + alerts] --- AUTH
Important distinctions:
- Authentication answers which principal connected.
- Authorization answers which topics/groups/operations that principal can access.
- TLS protects data in transit, not the authorization policy.
- Topic names and consumer groups are authorization resources; secure both.
- Kafka message payloads can still contain sensitive data visible to authorized consumers. Minimize payloads, control retention, and consider application-level encryption for especially sensitive fields.
- Protect credentials in client config and deployment secrets. Never put them in source control.
- Test producer, consumer, consumer-group, topic-creation, and admin permissions separately.
15. Cloud and infrastructure security
For AWS-like environments:
- use IAM roles/workload identities instead of long-lived access keys where possible;
- apply least privilege to roles, buckets, queues, KMS keys, databases, and deployment pipelines;
- use a secrets manager for passwords and API credentials;
- use KMS for key policy, audit, rotation, and envelope-encryption workflows;
- keep object storage private by default; block public access unless deliberately required;
- separate environments/accounts and restrict production access;
- protect snapshots, logs, backups, and replicas;
- use private networking as defense in depth, not as a substitute for authentication;
- continuously scan dependencies, images, IaC, and secrets;
- keep audit logs immutable or separately protected where appropriate.
Secrets lifecycle
flowchart TD GEN[Generate / provision secret] --> STORE[Store in secrets manager or KMS-backed system] STORE --> INJ[Workload obtains least-privilege access] INJ --> USE[Use at runtime; avoid logging] USE --> ROT[Rotate / revoke on schedule or incident] ROT --> MON[Audit access and alert on anomalies] MON --> STORE
Never bake secrets into container images, frontend bundles, Git history, or ordinary config files. Environment variables can be exposed through diagnostics or process inspection in some environments; use platform-supported secret injection and access controls.
16. Key management: the part that makes or breaks encryption
Ask these questions for every key:
- Who can create, use, rotate, disable, export, or delete it?
- Is it a data key, wrapping key, signing key, TLS private key, or password pepper?
- Where is it stored: KMS, HSM, OS keystore, or application memory?
- How are permissions separated from application data access?
- What is the rotation strategy? Can old ciphertext still be decrypted?
- What happens if a key is compromised or accidentally deleted?
- Are key use and policy changes audited?
- How are backups and disaster recovery handled?
Key rotation is not magic
Rotating a key does not automatically re-encrypt old data, invalidate every token, or revoke every copy of the old key. Define the exact lifecycle for each key type.
17. Common misconceptions and design traps
| Misconception | Correct mental model |
|---|---|
| “SHA-256 encrypts data.” | It hashes; there is no decryption key. |
| “Hashing a password with SHA-256 is enough.” | Use adaptive password hashing with salt. |
| “RSA encrypts all my data.” | Use symmetric AEAD for bulk data; public-key crypto often protects keys or signatures. |
| “A signed JWT is encrypted.” | A normal signed JWT is readable; signature is integrity/authenticity, not secrecy. |
| “HTTPS means the backend is secure.” | TLS protects a network hop; authorization and input validation remain necessary. |
| “Private VPC means Kafka is safe.” | Use authentication, ACLs, TLS, and least privilege. |
| “Encryption at rest stops a compromised app.” | An authorized app can usually decrypt/read data. |
| “CORS blocks API attackers.” | CORS is a browser policy, not server authorization. |
| “A certificate contains the private key.” | The certificate normally contains public identity/key information; private key stays protected. |
| “A stronger algorithm fixes poor key management.” | Key storage, access, rotation, and policy are equally critical. |
18. End-to-end secure e-commerce architecture
flowchart TB Browser[Browser / Mobile] --> CDN[CDN + WAF + DDoS controls] CDN --> LB[Load balancer: HTTPS TLS] LB --> API[API services] API --> AUTH[OIDC identity provider] API --> POLICY[Object-level authorization] API --> DB[(Database: private network + encryption at rest)] API --> KAFKA[Kafka: TLS + SASL/mTLS + ACLs] API --> S3[Private object storage] API --> SM[Secrets manager / KMS] KAFKA --> WORKERS[Consumers / workers] WORKERS --> DB DB --> BACKUP[Encrypted backups with restricted access] API --> LOG[Central logs, metrics, traces, audit] KAFKA --> LOG DB --> LOG
Walk through a payment request
- The client connects over HTTPS and validates the server certificate.
- The identity provider authenticates the user; the API validates the session/token.
- The API checks permission to perform the action and ownership of the specific order.
- The API validates amount, currency, order state, and idempotency key on the server.
- It writes the business state transactionally and publishes an event using an outbox/reliable messaging design where required.
- Kafka clients authenticate; ACLs limit topic and group operations; traffic is encrypted.
- Database disks, snapshots, and object storage are encrypted with managed keys and least-privilege access.
- Logs record actor, action, target, outcome, correlation ID, and time—but never passwords, tokens, card secrets, or private keys.
- Alerts detect unusual login attempts, denied access, privilege changes, key use, and traffic spikes.
- Incident response can revoke credentials, rotate keys, disable access, and restore from protected backups.
19. A practical learning sequence
- CIA triad, threat modeling, trust boundaries, STRIDE.
- Hashing versus MAC versus encryption versus signatures.
- MD5/SHA-1/SHA-2/SHA-3 and HMAC in Java.
- Password hashing, salts, peppers, password encoders.
- AES-GCM and nonce/key management.
- RSA, signatures, key pairs, hybrid encryption.
- PKI, certificates, keystores, TLS handshake.
- Authentication, authorization, sessions, JWT, OAuth2/OIDC.
- REST/API threats and secure Java coding.
- Kafka authentication, TLS, ACLs, payload/data governance.
- Encryption at rest, KMS, secrets, backups, rotation.
- Threat-model and defend a complete distributed system.
20. Further reading: primary and high-quality sources
- OWASP Password Storage Cheat Sheet — password hashing, salts, work factors.
- OWASP Cryptographic Storage Cheat Sheet — storage encryption and key management.
- OWASP Transport Layer Security Cheat Sheet — TLS deployment guidance.
- OWASP REST Security Cheat Sheet — API controls.
- OWASP API Security Top 10 — common API risk categories.
- Oracle Java Security Standard Algorithm Names — JCA/JCE algorithm names and support.
- Java Secure Coding Guidelines — Java security practices.
- RFC 8446: TLS 1.3 — protocol specification.
- RFC 8017: PKCS #1 / RSA — RSA encryption and signature schemes.
- NIST FIPS 180-4: Secure Hash Standard — SHA-2 family standard.
- NIST FIPS 202: SHA-3 Standard — SHA-3 and SHAKE.
- Apache Kafka Security — TLS, SASL, authorization, ACLs.
- OWASP Cheat Sheet Series — broader application security reference.
Standards change
Algorithm recommendations and framework APIs evolve. For production choices, verify the current OWASP/NIST/framework guidance, your compliance requirements, and your platform’s supported cryptographic providers. Do not copy sample parameters into production without reviewing them.
Related Notes
- Security Interview Playbook
- CS-1.1 Security Quick Reference
- DD-2.x Java Security Implementation (create as implementation exercises expand)
- 96-System-Design
- 97-Interview
Follow-up Questions
- Security Interview Playbook > Cryptography and password storage
- Security Interview Playbook > TLS and PKI
- Security Interview Playbook > REST and identity
- Security Interview Playbook > Kafka and distributed systems
- Security Interview Playbook > Architect-level scenarios
References
See Further reading above.