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 @Pattern with message = "VDE02"
  • Nested objects have @Valid to cascade validation
  • ValidationExceptionMapper is 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:

  • authorization
  • cookie
  • x-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 finally block — ALWAYS, even if the main logic throws
  • Use AsyncMdcRunner to 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 in finally with asyncRunner.run()
  • traceId read from RequestContext.getRequestId(), not hardcoded
  • If traceId is null, fallback to "UNKNOWN" (not empty string)
  • inputData and outputData serialized with ObjectMapper (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:

  • traceId in response (for client correlation) — implemented in MdcLoggingFilter
  • Content-Type: application/json automatic with JAX-RS
  • X-Content-Type-Options: nosniff — add if exposed to browser clients
  • Cache-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