refactor: full-stack restructure with multi-tenancy, workspace management, and K8s diagnostics
- Add Workspace domain (entity, repository, service, handler, DTO) - Add multi-tenant K8s client with tenant binding and quota management - Add K8s diagnostics client (instance diagnostics) - Add authorization middleware (authz package) - Restructure frontend to feature-based architecture (features/) - Add User Management page in configuration - Add AccessDenied page and route guards - Refactor shared components (form inputs, layout, UI) - Update Tailwind config for new design system - Add comprehensive documentation (docs/, tasks/, plans) - Improve cluster service with better kubeconfig handling - Add tests for crypto, config, helm client, tenant binding
This commit is contained in:
284
docs/security/bugs-security.md
Normal file
284
docs/security/bugs-security.md
Normal file
@ -0,0 +1,284 @@
|
||||
# OCDP Security Audit Report
|
||||
|
||||
**Date:** 2026-05-11
|
||||
**Target:** http://10.6.80.114:18080
|
||||
**API Base:** http://10.6.80.114:18080/api/v1
|
||||
|
||||
---
|
||||
|
||||
## Finding 1: User Enumeration via Login Error Messages
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | Authentication Error Disclosure |
|
||||
| **Severity** | **Medium** |
|
||||
| **Endpoint** | `POST /api/v1/auth/login` |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
# Non-existent user
|
||||
curl -s -X POST http://10.6.80.114:18080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"nonexistent_user_xyz","password":"test123"}'
|
||||
|
||||
# Existing user with wrong password
|
||||
curl -s -X POST http://10.6.80.114:18080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"wrongpassword"}'
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
Both requests should return the same generic error message (e.g., "Invalid credentials") to prevent username enumeration.
|
||||
|
||||
### Actual
|
||||
|
||||
- Non-existent user: `{"error":"Login failed","message":"user not found","code":401}`
|
||||
- Existing user: `{"error":"Login failed","message":"invalid password","code":401}`
|
||||
|
||||
The error messages are different, allowing an attacker to determine whether a username exists in the system.
|
||||
|
||||
### Impact
|
||||
|
||||
An attacker can enumerate valid usernames by observing the error message difference. This is the first step in a targeted brute force or credential stuffing attack.
|
||||
|
||||
### Recommendation
|
||||
|
||||
Return identical error messages for both cases, e.g., `"Invalid username or password"`.
|
||||
|
||||
---
|
||||
|
||||
## Finding 2: No Rate Limiting on Login Endpoint
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | Brute Force Protection |
|
||||
| **Severity** | **Medium** |
|
||||
| **Endpoint** | `POST /api/v1/auth/login` |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
for i in $(seq 1 10); do
|
||||
curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST http://10.6.80.114:18080/api/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"wrongpassword"}'
|
||||
done
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
After a threshold (e.g., 5 failed attempts), the server should return HTTP 429 Too Many Requests or temporarily lock the account.
|
||||
|
||||
### Actual
|
||||
|
||||
All 10 rapid sequential attempts returned HTTP 401. No rate limiting, no account lockout, no progressive delay.
|
||||
|
||||
### Impact
|
||||
|
||||
An attacker can brute force passwords without restriction. Combined with Finding 1 (user enumeration), the attack surface is increased.
|
||||
|
||||
### Recommendation
|
||||
|
||||
- Implement rate limiting on the login endpoint (e.g., max 5 attempts per minute per IP).
|
||||
- Consider account lockout after N failed attempts.
|
||||
- Add progressive response delays after repeated failures.
|
||||
|
||||
---
|
||||
|
||||
## Finding 3: Server Version Disclosure
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | Information Disclosure |
|
||||
| **Severity** | **Low** |
|
||||
| **Endpoint** | All (HTTP response headers) |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
curl -s -D - http://10.6.80.114:18080/ | head -10
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
Server header should be generic (e.g., `Server: nginx`) or removed entirely.
|
||||
|
||||
### Actual
|
||||
|
||||
```http
|
||||
Server: nginx/1.27.5
|
||||
```
|
||||
|
||||
### Impact
|
||||
|
||||
Knowing the exact nginx version helps attackers target known vulnerabilities for that specific version.
|
||||
|
||||
### Recommendation
|
||||
|
||||
Disable or obfuscate the Server header in nginx configuration:
|
||||
|
||||
```nginx
|
||||
server_tokens off;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Finding 4: Permissive CORS Policy
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | CORS Misconfiguration |
|
||||
| **Severity** | **Low** |
|
||||
| **Endpoint** | All API endpoints |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
curl -s -D - http://10.6.80.114:18080/api/v1/auth/login \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-d '{"username":"test","password":"test"}'
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
CORS `Access-Control-Allow-Origin` should be restricted to the application's origin (e.g., `http://10.6.80.114:18080`) rather than allowing all origins.
|
||||
|
||||
### Actual
|
||||
|
||||
```http
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Allow-Credentials: true
|
||||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
||||
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
|
||||
Access-Control-Max-Age: 86400
|
||||
```
|
||||
|
||||
### Impact
|
||||
|
||||
Any website can make cross-origin requests to the API. If a user is logged in, a malicious site could potentially make authenticated API calls on their behalf (CSRF-style attack, though mitigated by the Bearer token requirement).
|
||||
|
||||
### Recommendation
|
||||
|
||||
Restrict `Access-Control-Allow-Origin` to the specific frontend origin(s) instead of `*`.
|
||||
|
||||
---
|
||||
|
||||
## Finding 5: Missing Security Headers
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | Security Headers Audit |
|
||||
| **Severity** | **Low** |
|
||||
| **Endpoint** | All |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
curl -s -D - http://10.6.80.114:18080/ | head -20
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
Security headers should include:
|
||||
- `Strict-Transport-Security`
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-Frame-Options: DENY`
|
||||
- `Content-Security-Policy`
|
||||
|
||||
### Actual
|
||||
|
||||
None of these security headers are present in responses.
|
||||
|
||||
### Impact
|
||||
|
||||
Increases attack surface for clickjacking, MIME-type confusion, and XSS attacks.
|
||||
|
||||
### Recommendation
|
||||
|
||||
Add the following headers to nginx configuration:
|
||||
|
||||
```
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "0" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Finding 6: `/health` Endpoint Returns HTML Instead of Health Status
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Test** | Health Endpoint Behavior |
|
||||
| **Severity** | **Low** |
|
||||
| **Endpoint** | `GET /health` |
|
||||
| **Status** | Confirmed |
|
||||
|
||||
### What I Did
|
||||
|
||||
```bash
|
||||
curl -s http://10.6.80.114:18080/health
|
||||
```
|
||||
|
||||
### Expected
|
||||
|
||||
A health check endpoint should return a structured JSON response (e.g., `{"status":"healthy"}`) with HTTP 200.
|
||||
|
||||
### Actual
|
||||
|
||||
Returns the full `index.html` SPA page with HTTP 200:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>OCDP Platform</title>
|
||||
...
|
||||
```
|
||||
|
||||
### Impact
|
||||
|
||||
Not a direct vulnerability, but misconfigured health checks can cause false positives in monitoring/load balancer health checks. It also means the SPA is served at `/health`, which is unexpected.
|
||||
|
||||
### Recommendation
|
||||
|
||||
Implement a dedicated health endpoint that returns `{"status":"ok"}` with appropriate content type, or remove the `/health` route if not needed.
|
||||
|
||||
---
|
||||
|
||||
## Tests Passed (No Issues Found)
|
||||
|
||||
| Test | Result |
|
||||
|------|--------|
|
||||
| **1. Unauthenticated Access** | **PASS** - All business endpoints return 401 |
|
||||
| **2. JWT Token Manipulation** | **PASS** - Tampered tokens, alg=none, invalid formats all rejected (401) |
|
||||
| **3. XSS/SQLi Testing** | **PASS** - Script injection, SQLi patterns safely handled |
|
||||
| **4. IDOR - Instance Access** | **PASS** - No instances deployed to test; cluster/registry isolation confirmed working |
|
||||
| **5. Sensitive Data Masking** | **PASS** - Cluster certs/keys and registry passwords masked as `••••••••` |
|
||||
| **6. Self-Registration** | **PASS** - Registration endpoint requires authentication (401) |
|
||||
| **7. Path Traversal** | **PASS** - Path traversal attempts return index.html (not /etc/passwd) |
|
||||
| **8. Admin Permission Escalation** | **PASS** - Regular users blocked from admin endpoints (403) |
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Severity | Count | Findings |
|
||||
|----------|-------|----------|
|
||||
| Critical | 0 | — |
|
||||
| High | 0 | — |
|
||||
| **Medium** | **2** | User enumeration, No rate limiting |
|
||||
| **Low** | **4** | Server version disclosure, Permissive CORS, Missing security headers, `/health` returns HTML |
|
||||
| **Total** | **6** | |
|
||||
|
||||
The platform's core security controls (authentication, JWT validation, authorization, sensitive data masking) are properly implemented. The main areas for improvement are authentication hardening (rate limiting, user enumeration) and HTTP security hardening (headers, CORS).
|
||||
Reference in New Issue
Block a user