Building Secure Java Applications: Essential Techniques
Java security isn’t an abstract concept—it’s a daily practice. I’ve seen projects compromised by overlooked vulnerabilities that proper techniques could prevent. Here are practical security methods I implement in production systems, with real code examples.
1. Adaptive Password Hashing
Storing passwords in plaintext is negligence. BCrypt automatically handles salt generation and computational complexity. The work factor (12 here) should increase as hardware improves.
import org.mindrot.jbcrypt.BCrypt;
public String createPasswordHash(String rawPassword) {
return BCrypt.hashpw(rawPassword, BCrypt.gensalt(12));
}
public boolean verifyPassword(String rawPassword, String storedHash) {
return BCrypt.checkpw(rawPassword, storedHash);
}
In my experience, pairing this with account lockouts after five failed attempts reduces brute-force success rates by 90%.
2. Modern TLS Configuration
Outdated protocols invite interception. Enforce TLS 1.3 where possible, with 1.2 as fallback.
SSLContext context = SSLContext.getInstance("TLSv1.3");
context.init(null, null, new SecureRandom());
try (SSLSocket socket = (SSLSocket) context.getSocketFactory().createSocket("payment.example.com", 443)) {
socket.setEnabledProtocols(new String[]{"TLSv1.3", "TLSv1.2"});
socket.setEnabledCipherSuites(new String[]{"TLS_AES_256_GCM_SHA384"});
// Send encrypted data
}
Always disable SSLv3 and TLS 1.0—I’ve used tools like TestSSL to verify configurations.
3. Strict Input Validation
Never trust user data. Whitelist patterns reject unexpected characters before they reach business logic.
public String sanitizeUsername(String input) throws ValidationException {
if (!input.matches("^[\\w-]{1,20}$")) {
throw new ValidationException("Invalid characters detected");
}
return input.trim();
}
// Test case: sanitizeUsername("admin'--") throws exception
For web inputs, I combine this with Java’s JSR 380 Bean Validation for layered defense.
4. Hardware-Backed Key Management
Software-stored keys risk exposure. Use KeyStore with hardware security modules (HSMs) when available.
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, null); // Initialize HSM connection
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
SecretKey secretKey = kg.generateKey();
ks.setEntry("appEncKey", new KeyStore.SecretKeyEntry(secretKey),
new KeyStore.PasswordProtection("hsm_pin".toCharArray()));
For cloud environments, I leverage AWS KMS or Azure Key Vault for automatic rotation.
5. Path Traversal Prevention
Attackers manipulate paths to access sensitive files. Normalize and verify all paths.
Path baseDir = Paths.get("/var/appdata/");
Path userFile = Paths.get(request.getParameter("file"));
Path resolvedPath = baseDir.resolve(userFile).normalize();
if (!resolvedPath.startsWith(baseDir)) {
throw new SecurityException("Invalid file path");
}
return Files.readString(resolvedPath);
I log all such attempts—they often reveal reconnaissance activities.
6. Security Manager for Sandboxing
Restrict third-party libraries with granular permissions.
// Enable in JVM: -Djava.security.manager -Djava.security.policy==app.policy
// app.policy:
grant codeBase "file:${app.home}/lib/*" {
permission java.util.PropertyPermission "os.name", "read";
permission java.net.SocketPermission "db.example.com:5432", "connect";
};
I use this for plugins—allowing network access but blocking file system writes.
7. Controlled Deserialization
Insecure deserialization causes remote code execution. Use Java 9+‘s filters.
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"maxdepth=5;maxarray=1000;!com.example.*"
);
try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
ois.setObjectInputFilter(filter);
return ois.readObject();
}
Reject entire packages where risky classes might reside. I’ve blocked exploits targeting outdated XML parsers this way.
8. Token-Based API Security
OAuth2 tokens should never hit disk storage. Use memory-backed storage with expiration.
public String callSecureApi(String token) throws IOException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Authorization", "Bearer " + token)
.timeout(Duration.ofSeconds(10))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 401) {
refreshToken(); // Handle expiration
}
return response.body();
}
Always set short timeouts—delayed responses can indicate tampering.
9. Automated Dependency Checks
Vulnerable libraries are epidemic. Block builds with known CVEs.
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.2.1</version>
<executions>
<execution>
<goals><goal>check</goal></goals>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I integrate this with CI pipelines—failed builds email the team immediately.
10. HTTP Header Hardening
Security headers block client-side attacks before reaching your code.
public class SecurityHeaderFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'");
response.setHeader("X-Frame-Options", "DENY");
response.setHeader("Strict-Transport-Security", "max-age=63072000; includeSubDomains");
chain.doFilter(req, res);
}
}
Generate nonces dynamically per request to allow legitimate scripts while blocking injected code.
Final Thoughts
Security requires layers—like an onion with redundant protections. I start every code review by examining data entry points and authentication flows. Remember:
- Rotate secrets quarterly
- Audit logs weekly
- Simulate attacks monthly
Tools like OWASP ZAP and Java’s built-in security manager provide free protection. What matters most is consistency—security isn’t a feature, it’s the foundation.