1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Security = never trust user input! SQL injection: Use PreparedStatement (not concatenation).
- XSS: Sanitize outputs, escape HTML.
- Input validation: Whitelist > blacklist.
- Authentication: Hash passwords (BCrypt, not MD5!), use tokens (JWT).
- Sensitive data: Never log passwords, use HTTPS, encrypt at rest.
- Dependencies: Update regularly, scan for vulnerabilities (OWASP).
- CSRF: Use tokens for state-changing requests.
- Golden rule: Assume all input is malicious. Security is not optional!
Think of home security. Input validation = check ID before entry. SQL injection = guest secretly brings in burglar. XSS = poisoned food. Password hashing = safe combination (not sticky note). HTTPS = armored car vs regular car for valuables!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- SQL Injection: Trojan horse (hidden attack)
- XSS: Poisoned gift (looks safe, isn't)
- Password Hashing: Shredded document (irreversible)
- Input Validation: Airport security (check everything)
3. Technical Mastery (The "Deep Dive")
java
// ===========================================
// 1. SQL INJECTION PREVENTION
// ===========================================
// ❌ CRITICAL VULNERABILITY: SQL Injection
String userId = request.getParameter("id");
String sql = "SELECT * FROM users WHERE id = '" + userId + "'";
// If userId = "1' OR '1'='1", returns ALL users!
// If userId = "1'; DROP TABLE users;--", DELETES TABLE!
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql); // ❌ NEVER DO THIS!
// ✅ SAFE: Prepared Statement (parameterized query)
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, Integer.parseInt(userId)); // ✅ Safely escapes input
ResultSet rs = stmt.executeQuery();
// ORM (JPA) is also safe
User user = entityManager.find(User.class, userId); // ✅ Safe
// ===========================================
// 2. XSS (Cross-Site Scripting) PREVENTION
// ===========================================
// ❌ VULNERABILITY: Reflecting user input
String comment = request.getParameter("comment");
response.getWriter().write("<div>" + comment + "</div>");
// If comment = "<script>alert('XSS')</script>", executes JavaScript!
// ✅ SAFE: Escape HTML
import org.apache.commons.text.StringEscapeUtils;
String comment = request.getParameter("comment");
String safeComment = StringEscapeUtils.escapeHtml4(comment);
response.getWriter().write("<div>" + safeComment + "</div>");
// "<script>" becomes "<script>" (displayed, not executed)
// ✅ SAFE: Use templating engines (Thymeleaf, JSP with JSTL)
// Thymeleaf auto-escapes by default
// <div th:text="${comment}"></div> <!-- Auto-escaped! -->
// ===========================================
// 3. INPUT VALIDATION
// ===========================================
// ❌ BAD: Blacklist (incomplete)
if (input.contains("script") || input.contains("SQL")) {
// Block
}
// Bypass: "scr<script>ipt", "Sql", etc.
// ✅ GOOD: Whitelist (explicit allowed values)
Pattern emailPattern = Pattern.compile("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$");
if (!emailPattern.matcher(email).matches()) {
throw new ValidationException("Invalid email");
}
// ✅ GOOD: Use validation libraries
import javax.validation.constraints.*;
class User {
@Email
@NotEmpty
private String email;
@Min(0)
@Max(150)
private int age;
}
// ===========================================
// 4. PASSWORD SECURITY
// ===========================================
// ❌ CRITICAL: Storing plaintext passwords
String password = "secret123";
database.save(user.getId(), password); // ❌ NEVER!
// ❌ CRITICAL: Weak hashing (MD5, SHA-1)
String hash = MessageDigest.getInstance("MD5")
.digest(password.getBytes()); // ❌ Easily cracked!
// ✅ SAFE: BCrypt (slow hash, with salt)
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode("secret123");
database.save(user.getId(), hashedPassword);
// Verify password
boolean matches = encoder.matches("secret123", hashedPassword);
// ✅ SAFE: Argon2 (winner of Password Hashing Competition)
import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
// ===========================================
// 5. SENSITIVE DATA HANDLING
// ===========================================
// ❌ BAD: Logging sensitive data
logger.info("User login: " + username + ", password: " + password); // ❌ NEVER!
logger.info("Credit card: " + creditCard); // ❌ NEVER!
// ✅ GOOD: Don't log sensitive data
logger.info("User login: " + username); // ✅ No password!
// ✅ GOOD: Mask sensitive data
String masked = creditCard.substring(0, 4) + "********" +
creditCard.substring(creditCard.length() - 4);
logger.info("Payment with card: " + masked); // 1234********5678
// ===========================================
// 6. AUTHENTICATION & AUTHORIZATION
// ===========================================
// ✅ Token-based auth (JWT)
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
String token = Jwts.builder()
.setSubject(user.getId())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hour
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
// Verify token
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
// ✅ Role-based access control
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(int userId) {
// Only admins can execute
}
// ===========================================
// 7. DEPENDENCY VULNERABILITIES
// ===========================================
// ✅ Scan dependencies (Maven)
// pom.xml
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.0.0</version>
</plugin>
// Run: mvn dependency-check:check
// ✅ Keep dependencies updated
// Check: mvn versions:display-dependency-updates
// ===========================================
// 8. CSRF PREVENTION
// ===========================================
// ❌ VULNERABLE: No CSRF protection
@PostMapping("/transfer")
public void transfer(@RequestParam int amount) {
// ❌ Attacker can trigger this via hidden form!
}
// ✅ SAFE: CSRF token (Spring Security)
// Automatically includes CSRF token in forms
<form method="POST" action="/transfer">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="number" name="amount"/>
<button type="submit">Transfer</button>
</form>5. The Comparison & Decision Layer
| Vulnerability | Attack | Prevention |
|---|---|---|
| SQL Injection | Malicious SQL | PreparedStatement |
| XSS | Malicious JavaScript | Escape HTML output |
| Weak Passwords | Brute force | BCrypt/Argon2 |
| CSRF | Forged requests | CSRF tokens |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Explain SQL injection and how to prevent it." Answer: SQL injection = attacker injects malicious SQL via user input!
Vulnerable code:
java
String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";
// If userInput = "admin' OR '1'='1", becomes:
// SELECT * FROM users WHERE name = 'admin' OR '1'='1'
// Returns ALL users (bypasses authentication)!Prevention:
java
// Use PreparedStatement (parameterized queries)
String sql = "SELECT * FROM users WHERE name = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, userInput); // ✅ Safely escaped!Pro-Tips (OWASP Top 10):
- Input validation:
java
// Validate everything!
@NotNull
@Email
private String email;
@Min(0)
@Max(150)
private int age;
// Whitelist allowed characters
if (!input.matches("[a-zA-Z0-9]+")) {
throw new ValidationException();
}- Security headers (Spring Security):
java
http.headers()
.contentSecurityPolicy("default-src 'self'")
.xssProtection()
.frameOptions().deny();