4.7 KiB
4.7 KiB
name, description, source
| name | description | source |
|---|---|---|
| security-best-practices | Security review for banking APIs — headers, input validation, log masking, and trace integrity. | community + V4 banking patterns (pinned 2026-03-19) |
Security Best Practices for Banking APIs
Overview
Review and enforce security practices in API implementations, with focus on banking-grade requirements: input validation, header sanitization, log masking, and trace integrity.
When to Use
- Reviewing header handling in Resources and Adapters
- Validating input sanitization on DTOs
- Auditing log filters for sensitive data exposure
- Verifying trace integrity (SecurityTracePort)
- Pre-delivery security review
Instructions
1. Input Validation
Every input field MUST have explicit validation:
// ✅ Correct — validation codes tied to error catalog
@NotNull(message = "VDE01")
@Valid
private CustomerReference customerReference;
// ✅ Correct — pattern restricts to known values
@NotNull(message = "VDE01")
@Pattern(regexp = "^[VEJPGCR]$", message = "VDE02")
private String customerIdType;
// ❌ Incorrect — no validation
private String customerIdType;
// ❌ Incorrect — validation without error code
@NotNull
private String customerId;
Checklist:
- All required fields have
@NotNull(message = "VDE01") - Enum-like fields have
@Patternwithmessage = "VDE02" - Nested objects have
@Validto cascade validation ValidationExceptionMapperis present and registered as@Provider
2. Header Security
Required headers MUST be validated:
// ✅ Correct — declared as required with description
@Parameter(description = "Application ID", required = true)
@HeaderParam("appId") String appId,
// The MdcLoggingFilter handles null → "UNKNOWN_APP" fallback
// But the Resource should still declare them as required
Headers that MUST NOT be logged without masking:
authorizationcookiex-api-key- Any custom credentials header
Implementation in RestClientLoggingFilter:
private static final Set<String> SENSITIVE_HEADERS =
Set.of("authorization", "cookie", "x-api-key");
// Mask: "authorization=[PROTECTED]"
3. Log Masking
PII and sensitive data MUST be masked in production logs:
| Data Type | Log Level Allowed | Masking Rule |
|---|---|---|
customerId |
DEBUG only | Never in INFO |
customerIdType |
DEBUG only | Never in INFO |
deviceIp |
INFO | OK — used for fraud detection |
traceId / deviceSessionReference |
INFO | OK — correlation ID |
appId |
INFO | OK — non-sensitive identifier |
| Authorization headers | NEVER | [PROTECTED] |
Rule: In %prod profile, only com.banesco level INFO. Never expose PII at INFO level.
4. Trace Integrity
The SecurityTracePort MUST:
- Execute in
finallyblock — ALWAYS, even if the main logic throws - Use
AsyncMdcRunnerto preserve MDC context in the async thread - Never block the main response thread
- Handle its own exceptions silently (log ERROR, don't propagate)
Checklist:
writeTrace()called infinallywithasyncRunner.run()traceIdread fromRequestContext.getRequestId(), not hardcoded- If
traceIdis null, fallback to"UNKNOWN"(not empty string) inputDataandoutputDataserialized withObjectMapper(not.toString())- Trace failure logged as ERROR but NEVER propagated to caller
5. ConfigMap Security
Environment variables for URLs MUST use the pattern:
url: ${INTEGRATION_<SERVICE>_URL:<default-dev-url>}
- Production URLs NEVER hardcoded in
application.yml - Dev URLs can be hardcoded as defaults for convenience
- Credentials NEVER in
application.yml— use Kubernetes Secrets
6. HTTP Security Headers
Response headers to consider:
traceIdin response (for client correlation) — ✅ implemented inMdcLoggingFilterContent-Type: application/json— ✅ automatic with JAX-RSX-Content-Type-Options: nosniff— add if exposed to browser clientsCache-Control: no-store— banking APIs MUST NOT be cached
7. Security Review Output Format
## Security Review — <API Name>
### Input Validation
- [ ] All fields validated with error codes
- [ ] @Pattern on constrained fields
### Header Security
- [ ] Sensitive headers masked in logs
- [ ] Required headers declared in Resource
### Log Masking
- [ ] No PII at INFO level in prod
- [ ] SENSITIVE_HEADERS set includes all credential headers
### Trace Integrity
- [ ] SecurityTracePort in finally with AsyncMdcRunner
- [ ] TraceId not null/empty
### ConfigMap
- [ ] No hardcoded prod URLs
- [ ] No credentials in application.yml
### Overall Risk: LOW | MEDIUM | HIGH