Definition
- Sensitive data exposure – the failure to adequately protect confidential data at rest, in transit, and in logs, so it can be read by unauthorized parties.
- At rest – passwords stored in plaintext or weak hashes, unencrypted PII in databases.
- In transit – data sent over unencrypted HTTP instead of HTTPS/TLS.
- In logs – PII, tokens, card numbers, or passwords written to log files accessible to unauthorized staff.
- Defenses – bcrypt/Argon2 for passwords, TLS/HTTPS/HSTS everywhere, encryption at rest, masking in logs, secrets in a vault.
Sensitive data exposure is like National Bank of India writing customers' PINs on a public notice board (plaintext storage), shouting account details across the lobby (HTTP instead of HTTPS), and photocopying full card numbers into the daily diary that cleaners can read (PII in logs). The fixes are to store PINs only as scrambled irreversible codes, speak through a private sealed tube (TLS), and in any diary write only the last four digits of a card with the rest blacked out (masking).
Understanding the Concepts
What is sensitive data exposure?
Sensitive data exposure is the failure to adequately protect confidential data in its three states: at rest (stored), in transit (transmitted), and in logs (recorded). It lets unauthorized parties read data they should never see.
In banking, the exposed data is money, identity, and card details, making this especially dangerous.
Three states of data:
At rest: passwords, card numbers, PII in databases
In transit: data traveling over the network (HTTP vs HTTPS)
In logs: information written to log files, monitoring systems
Each state needs its own protection:
At rest: hash (passwords) or encrypt (PII, cards)
In transit: TLS/HTTPS everywhere
In logs: mask, redact, or omit sensitive fields
How do you protect passwords at rest?
Passwords must never be stored recoverably. Use a slow, salted hash like bcrypt, scrypt, or Argon2. These are one-way: even a database breach does not reveal passwords. Never use MD5, SHA-1, or plaintext.
package com.bank.security;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class PasswordProtection {
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(12);
public static void main(String[] args) {
String raw = "Rajesh@SecurePass2024";
// Store only the hash
String hash = ENCODER.encode(raw);
System.out.println("Stored: " + hash);
// $2a$12$... (irreversible)
// Verify on login
System.out.println("Matches: " + ENCODER.matches(raw, hash)); // true
System.out.println("Wrong: " + ENCODER.matches("wrong", hash)); // false
}
}
Stored: $2a$12$kR7xP2qM9nTvWz3Y...bcrypt_hash
Matches: true
Wrong: false
Even with full database access, attacker sees only irreversible hashes.
How do you protect data in transit?
Enforce TLS (HTTPS) everywhere. Redirect HTTP to HTTPS. Enable HSTS (Strict-Transport-Security) so browsers refuse plain HTTP. Use strong cipher suites. Internal service-to-service traffic should also use TLS.
package com.bank.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class TlsConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.requiresChannel(channel -> channel
.anyRequest().requiresSecure() // redirect HTTP to HTTPS
)
.headers(headers -> headers
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31536000) // 1 year
)
);
return http.build();
}
}
Response header:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Result: browser refuses plain HTTP for 1 year.
All data encrypted in transit with TLS.
How do you protect sensitive data in logs?
Never log passwords, full card numbers, tokens, or raw PII. Mask fields so only the last few characters show.
package com.bank.security;
public class LogMasker {
public static String maskCardNumber(String cardNumber) {
if (cardNumber == null || cardNumber.length() < 4) return "****";
return "****-****-****-" + cardNumber.substring(cardNumber.length() - 4);
}
public static String maskAccount(String accountId) {
if (accountId == null || accountId.length() < 4) return "****";
return "****" + accountId.substring(accountId.length() - 4);
}
public static String maskToken(String token) {
return "[REDACTED]";
}
public static void main(String[] args) {
System.out.println("Card: " + maskCardNumber("4532123456789012"));
System.out.println("Account: " + maskAccount("SAV2001"));
System.out.println("Token: " + maskToken("eyJhbGciOi..."));
}
}
Card: ****-****-****-9012
Account: ****2001
Token: [REDACTED]
Safe to write to logs. No sensitive data exposed.
How do you protect recoverable sensitive data at rest?
For data that must be read back (unlike passwords), use encryption at rest. Account numbers and PII can be encrypted with AES at the application level or with database-level transparent data encryption. Highly sensitive values like full card numbers should be tokenized.
package com.bank.security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.util.Base64;
public class DataEncryption {
public static void main(String[] args) throws Exception {
SecretKey key = KeyGenerator.getInstance("AES").generateKey();
// Encrypt
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal("SAV2001-Rajesh-Kumar".getBytes());
String stored = Base64.getEncoder().encodeToString(encrypted);
System.out.println("Encrypted: " + stored);
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(stored));
System.out.println("Decrypted: " + new String(decrypted));
}
}
Encrypted: kR7xP2qM9nTvWz3Y+5bC... (unreadable without key)
Decrypted: SAV2001-Rajesh-Kumar
Where should secrets be stored?
API keys, database passwords, and encryption keys must live in a secrets manager (Vault, AWS Secrets Manager, Azure Key Vault), not in source code or config files checked into version control.
WRONG:
application.yml: db.password=plaintext_password (in Git!)
Source code: String apiKey = "ABC123"; (in Git!)
CORRECT:
Environment variable: DB_PASSWORD (injected at deploy time)
Secrets manager: vault.read("secret/db-password")
Spring property: ${DB_PASSWORD} (resolved from env/vault)
What are common mistakes?
The most common mistake is logging full request bodies that contain passwords or tokens.
// WRONG: logging request body (contains password!)
log.info("Login request: " + requestBody);
// Output: Login request: {"username":"rajesh","password":"SecurePass2024"}
// CORRECT: log only safe fields
log.info("Login attempt for user: " + username);
// Output: Login attempt for user: rajesh
Another mistake is returning detailed error messages that leak internal information.
// WRONG: detailed error
return "Error: table 'accounts' column 'balance' not found at line 42";
// Leaks internal schema!
// CORRECT: generic error
return "An error occurred. Please try again.";
// Internal details logged server-side only
What about key management?
Encryption is only as strong as its key management. Keys must be rotated regularly, stored separately from the data they encrypt, and access-controlled. A compromised key compromises all data encrypted with it.
Key management best practices:
- Store keys in HSM or secrets manager, never alongside data
- Rotate keys on a schedule (e.g., every 90 days)
- Support key versioning: new data uses new key, old data decrypted with old key
- Audit key access
- Separate encryption keys from signing keys
What should a senior engineer know?
Senior engineers classify data into sensitivity levels and apply the appropriate control per level. They know that encryption without proper key management is security theater. They minimize data collection, set retention limits, and ensure that data at rest, in transit, and in logs all receive the right treatment.
Visual Overview
Three States of Data Protection: ┌──────────────────────────────────────────────┐ │ AT REST │ │ Passwords ──► bcrypt/Argon2 hash │ │ PII/Cards ──► AES encryption or tokenization │ │ Secrets ──► Vault / secrets manager │ ├──────────────────────────────────────────────┤ │ IN TRANSIT │ │ All traffic ──► TLS/HTTPS │ │ Browser ──► HSTS header │ │ Internal ──► Mutual TLS │ ├──────────────────────────────────────────────┤ │ IN LOGS │ │ Cards ──► ****-****-****-9012 │ │ Accounts ──► ****2001 │ │ Tokens ──► [REDACTED] │ │ Passwords ──► NEVER logged │ └──────────────────────────────────────────────┘
Key Takeaway
Sensitive data exposure is the failure to adequately protect confidential data in its three states: at rest, in transit, and in logs. The common causes are storing passwords in plaintext or weak hashes, sending data over plain HTTP instead of HTTPS, logging personally identifiable information or secrets, weak encryption of stored data, and leaking data in error messages. In a bank this is especially serious because the exposed data is money, identity, and card details.
The approach is to apply the right control to each state. For passwords and credentials at rest, use a slow, salted, one-way hash like bcrypt or Argon2, so even a full database breach yields hashes that cannot be reversed. For recoverable sensitive data like account numbers, use encryption at rest, and for the most sensitive values like full card numbers, use tokenization so the real number never sits in the main datastore. Secrets like API keys live in a vault, not in code, and are rotated.
For data in transit, enforce TLS everywhere, redirect HTTP to HTTPS, enable HSTS so browsers refuse plain HTTP, and use mutual TLS between internal services. For logs, which are a frequent leak point, mask sensitive fields so only the last four digits of an account or card show and redact tokens entirely.
The nuances to stress are classifying data so you know what is sensitive, minimizing what is collected and setting retention limits, returning generic error messages that do not leak internal details, and treating key management: rotation and separation of keys from data, as being just as important as the encryption itself.
Remember one sentence: protect data in all three states: hash passwords at rest, encrypt everything in transit with TLS, and mask sensitive fields in logs.
---