Primer - Java Secure Coding Guide
unattributed Guide to Java Secure Coding
Table of Contents
- unattributed Guide to Java Secure Coding
Introduction
This guide synthesizes Oracle’s Secure Coding Guidelines for Java SE (v10.0, May 2023), MITRE’s CWE Top 25, and modern secure development practices into a comprehensive technical resource. It provides senior developers and security professionals with:
- Actionable secure coding patterns
- IDE-specific security configurations
- Automated verification techniques
- Reference implementations for critical security controls
“To minimize the likelihood of security vulnerabilities caused by programmer error, Java developers should adhere to recommended coding guidelines.” - Oracle Secure Coding Guidelines
Core Security Principles
1. Fundamental Design Principles
Principle of Least Privilege (Oracle FUNDAMENTALS-3)
// Secure service design
public final class PaymentService {
private final PaymentProcessor processor;
@RolesAllowed("PAYMENT_ADMIN")
public void processPayment(PaymentRequest request) {
validateRequest(request);
processor.charge(request);
}
// Private constructor prevents instantiation
private PaymentService(PaymentProcessor processor) {
this.processor = processor;
}
}
Immutable Data Objects (Oracle MUTABLE-1)
public final class UserCredentials {
private final byte[] passwordHash;
private final byte[] salt;
public UserCredentials(byte[] password, byte[] salt) {
this.passwordHash = Arrays.copyOf(password, password.length);
this.salt = Arrays.copyOf(salt, salt.length);
}
// No setters, defensive copies on getters
public byte[] getPasswordHash() {
return Arrays.copyOf(passwordHash, passwordHash.length);
}
}
2. Input Validation (Oracle INPUT-1)
Comprehensive Validation Framework
// Jakarta Bean Validation 3.0 + Custom Constraints
public class UserInput {
@NotBlank @Size(max=100)
private String name;
@Email
private String email;
@Pattern(regexp="^[a-zA-Z0-9_\\-]{8,20}$")
private String username;
@SafeHTML
private String bio;
}
// Custom validator example
@Constraint(validatedBy = SafeHtmlValidator.class)
public @interface SafeHTML {
String message() default "Unsafe HTML content";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
CWE Top 25 Mitigations
Critical Web Application Risks
CWE | Risk | Java Mitigation | Verification |
---|---|---|---|
CWE-89 | SQL Injection |
// JPA Criteria API
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
q.where(cb.equal(
root.get("username"),
cb.parameter(String.class, "user")));
CWE | Risk | Java Mitigation | Verification |
---|---|---|---|
CWE-79 | XSS |
- Use OWASP Java Encoder - Validate and sanitize user input |
- SonarQube Rule S3649 - SpotBugs SQLI detector |
// OWASP Java Encoder
String safeOutput = Encode.forHtmlContent(untrustedInput);
Area | Check | Tool |
---|---|---|
Web Security | ZAP Active Scan | Check CSP headers |
System-Level Risks
CWE-502: Unsafe Deserialization
// Java 17 Serialization Filter
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"maxdepth=10;maxarray=1000;!org.apache.commons.collections4.*"
);
try (ObjectInputStream ois = new ObjectInputStream(input)) {
ois.setObjectInputFilter(filter);
return (Data) ois.readObject();
}
CWE-125: Buffer Overflow
// Java 16 Memory Access API
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment segment = MemorySegment.allocateNative(100, session);
// Bounds-checked access
int value = segment.get(ValueLayout.JAVA_INT, 0);
}
IDE Security Configuration
Visual Studio Code
Security Extensions:
- SonarLint
{ "sonarlint.ls.java.extraArgs": [ "-Dsonar.java.source=17", "-Dsonar.security.audit=true" ] }
- OWASP Dependency Check Task
{ "type": "shell", "command": "mvn org.owasp:dependency-check:check", "problemMatcher": "$dependency-check" }
IntelliJ IDEA
Security Analysis Setup:
- Inspection Profile
<profile name="Security Audit"> <inspection_tool class="SqlInjection" enabled="true" level="ERROR"/> <inspection_tool class="UnsafeDeserialization" enabled="true" level="ERROR"/> </profile>
- CodeQL Integration
codeql database create java-secure --language=java \ --command="mvn clean install"
Eclipse IDE
Secure Development Configuration:
- FindSecBugs Setup
<buildCommand> <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name> <arguments> <dictionary> <key>securityOnly</key> <value>true</value> </dictionary> </arguments> </buildCommand>
- ESAPI Validation
ESAPI.validator().setValidator( new DefaultValidator(ESAPI.securityConfiguration()) .setMaximumInputLength(256) .setAllowNull(false) );
Secure Development Workflows
Pre-Commit Hooks
#!/bin/sh
# Reject commits with security anti-patterns
git diff --cached | grep -E \
'ObjectInputStream|Runtime\.exec|ProcessBuilder' && \
echo "SECURITY REJECT: Dangerous pattern detected" && exit 1
CI/CD Pipeline
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: OWASP Dependency Check
run: mvn org.owasp:dependency-check:check
- name: SAST Analysis
uses: github/codeql-action/analyze@v2
with:
languages: java
queries: security-and-quality
- name: DAST Scan
uses: zaproxy/action-full-scan@v0.3.0
with:
target: 'http://localhost:8080'
Advanced Security Techniques
1. Cryptographic Controls
Secure Key Handling (CWE-320)
// Java KeyStore API with proper protection
KeyStore ks = KeyStore.getInstance("PKCS12");
try (InputStream is = Files.newInputStream(keystorePath)) {
ks.load(is, password);
}
Key key = ks.getKey("alias", keyPassword);
if (key instanceof SecretKey secretKey) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
}
2. Memory Safety
Foreign Memory API (Java 16+)
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment segment = MemorySegment.allocateNative(100, session);
// Type-safe access
segment.set(ValueLayout.JAVA_INT, 0, 42);
int value = segment.get(ValueLayout.JAVA_INT, 0);
}
3. Secure Serialization
JEP 415: Context-Specific Filters
ObjectInputFilter.Config.setSerialFilterFactory((info) -> {
if (info.serialClass() != null &&
info.serialClass().getName().startsWith("com.safe.")) {
return ObjectInputFilter.Status.ALLOWED;
}
return ObjectInputFilter.Status.REJECTED;
});
Security Verification Checklists
Code Review Checklist
- [ ] **Input Validation**
- [ ] All entry points validate CWE-20
- [ ] Regex anchors used (CWE-777)
- [ ] Custom validators for business logic
- [ ] **Cryptography**
- [ ] No custom algorithms (CWE-327)
- [ ] Proper IV/nonce usage (CWE-329)
- [ ] Key rotation implemented
- [ ] **Error Handling**
- [ ] No system details leaked (CWE-209)
- [ ] Finalizers not relied upon (CWE-586)
Production Readiness Audit
Area | Check | Tool |
---|---|---|
Dependencies | No known vulnerabilities | OWASP DC |
APIs | Rate limiting enabled | ZAP |
Config | No default credentials | Checkspec |
References and Attribution
-
Oracle Secure Coding Guidelines for Java SE
Document version: 10.0, May 2023
https://www.oracle.com/java/technologies/javase/seccodeguide.html -
MITRE CWE Top 25 Most Dangerous Software Weaknesses
2023 Edition
https://cwe.mitre.org/top25/ -
OWASP Java Secure Coding Practices
https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/ -
Java Security Evolution
Inside Java Security Articles
https://inside.java/tag/security/
unattributed makes zero promises that this document will be periodically updated to reflect new threats and defensive techniques, as always keep hunting.