153 lines
4.7 KiB
Markdown
153 lines
4.7 KiB
Markdown
---
|
|
name: security-best-practices
|
|
description: Security review for banking APIs — headers, input validation, log masking, and trace integrity.
|
|
source: 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:**
|
|
|
|
```java
|
|
// ✅ 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:**
|
|
|
|
```java
|
|
// ✅ 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`:**
|
|
```java
|
|
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:**
|
|
```yaml
|
|
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
|
|
|
|
```markdown
|
|
## 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
|
|
```
|