Java Application Security
Learn secure input handling, authentication and authorization concepts, cryptography basics, secrets, deserialization risks, and secure dependency practices.
Input Validation and Output Encoding
Treat all external input as untrusted: HTTP parameters, JSON bodies, headers, uploaded files, messages, and untrusted external data.
if (username == null || !username.matches("[A-Za-z0-9_]{3,32}")) {
throw new IllegalArgumentException("Invalid username");
}
Validation is not only about security. It protects downstream components from malformed data and makes API behavior predictable. Output encoding must be appropriate for its context.
- Validate at trust boundaries.
- Use context-specific encoding and safe APIs.
- Validation for one sink does not automatically protect another sink.
Cryptography and Secret Management
Use standard cryptographic libraries rather than implementing algorithms yourself. Passwords should be stored using dedicated password hashing rather than reversible encryption or fast hashes.
Secrets such as API keys and database passwords should come from secure secret management rather than source control.
// Conceptual:
// secret = secretManager.get("payments/api-key");
// client.authenticate(secret);
Encryption, hashing, signing, and key derivation are different operations with different purposes.
Treat leaked credentials as compromised; rotate them and use secret management.
- Do not implement cryptographic primitives yourself.
- Use dedicated password hashing for passwords.
- Keep secrets out of source code and ordinary logs.
Deserialization and Dependency Security
Java applications depend heavily on third-party libraries. A vulnerability in a transitive dependency can become a production risk.
Use dependency scanning, timely patching, software bills of materials where appropriate, and minimal dependency sets. For deserialization, prefer explicit schemas and constrained types over arbitrary object graphs from untrusted input.
mvn dependency:tree
./gradlew dependencies
Security is a lifecycle concern: secure coding, dependency management, CI scanning, runtime hardening, logging, incident response, and patching all matter.
- Transitive dependencies are part of your attack surface.
- Prefer explicit data formats for untrusted input.
- Security needs continuous maintenance.