Files
api-wipay/FAST_API_HARDENING.md

439 lines
9.3 KiB
Markdown
Raw Normal View History

# 🔒 FAST API HARDENING - IMPLEMENTASI
## ✅ Status: HARDENING COMPLETED
---
## 🎯 FITUR HARDENING YANG DIIMPLEMENTASI
### **1. Rate Limiting** ✅
**Implementasi:**
- ✅ File-based rate limiting (bisa upgrade ke Redis nanti)
- ✅ Default: **100 requests per minute** per API key
- ✅ Configurable per API key via database
- ✅ Response headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`
- ✅ Return **429 Too Many Requests** jika limit exceeded
**Location:**
- `src/Helpers/RateLimitHelper.php` - `checkRateLimit()`
- `src/Middleware/ApiKeyMiddleware.php` - Rate limit check
**Configuration:**
```sql
-- Set custom rate limit per API key
UPDATE api_keys
SET rate_limit_per_minute = 200,
rate_limit_window = 60
WHERE id = 1;
```
**Response Headers:**
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705123456
Retry-After: 45
```
---
### **2. IP Whitelist** ✅
**Implementasi:**
- ✅ IP whitelist per API key (optional)
- ✅ Support single IP atau CIDR notation (e.g., `192.168.1.0/24`)
- ✅ Support comma-separated atau JSON array
- ✅ Default: **disabled** (allow all IPs)
- ✅ Return **403 Forbidden** jika IP tidak di whitelist
**Location:**
- `src/Helpers/RateLimitHelper.php` - `checkIpWhitelist()`
- `src/Middleware/ApiKeyMiddleware.php` - IP whitelist check
**Configuration:**
```sql
-- Enable IP whitelist untuk API key
UPDATE api_keys
SET enable_ip_whitelist = 1,
ip_whitelist = '192.168.1.100,10.0.0.0/24,203.0.113.0/24'
WHERE id = 1;
-- Atau menggunakan JSON array
UPDATE api_keys
SET enable_ip_whitelist = 1,
ip_whitelist = '["192.168.1.100", "10.0.0.0/24"]'
WHERE id = 1;
```
**Format IP Whitelist:**
- Single IP: `192.168.1.100`
- CIDR: `192.168.1.0/24`
- Comma-separated: `192.168.1.100,10.0.0.0/24`
- JSON array: `["192.168.1.100", "10.0.0.0/24"]`
---
### **3. API Key Expiration** ✅
**Implementasi:**
- ✅ Expiration date per API key (optional)
- ✅ Check expiration saat validation
- ✅ Return **401 Unauthorized** jika expired
- ✅ Default: **never expires** (NULL)
**Location:**
- `src/Helpers/RateLimitHelper.php` - `checkExpiration()`
- `src/Middleware/ApiKeyMiddleware.php` - Expiration check
**Configuration:**
```sql
-- Set expiration date untuk API key
UPDATE api_keys
SET expires_at = '2025-12-31 23:59:59'
WHERE id = 1;
-- Remove expiration (never expires)
UPDATE api_keys
SET expires_at = NULL
WHERE id = 1;
```
---
### **4. Request Timestamp Validation** ✅
**Implementasi:**
- ✅ Optional timestamp validation untuk prevent replay attack
- ✅ Default: **disabled** (log only, tidak block)
- ✅ Max age: **5 minutes** (300 seconds)
- ✅ Header: `X-Timestamp` atau body `timestamp`
**Location:**
- `src/Helpers/RateLimitHelper.php` - `validateTimestamp()`
- `src/Middleware/ApiKeyMiddleware.php` - Timestamp validation
**Usage:**
```http
POST /fast/check_bill
X-Client-ID: your_client_id
X-Client-Secret: your_client_secret
X-Timestamp: 1705123456
```
**Enable Blocking:**
Uncomment line di `ApiKeyMiddleware.php`:
```php
// Uncomment untuk block request dengan timestamp invalid
return ResponseHelper::json($handler->handle($request)->withStatus(400),
['status' => 'error', 'message' => $timestampValidation['message']], 400);
```
---
## 📊 DATABASE SCHEMA
### **New Columns di `api_keys` Table:**
```sql
ALTER TABLE api_keys
ADD COLUMN rate_limit_per_minute INT DEFAULT 100,
ADD COLUMN rate_limit_window INT DEFAULT 60,
ADD COLUMN enable_ip_whitelist TINYINT(1) DEFAULT 0,
ADD COLUMN ip_whitelist TEXT NULL,
ADD COLUMN expires_at DATETIME NULL,
ADD COLUMN last_used_at DATETIME NULL,
ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
-- Indexes
CREATE INDEX idx_api_keys_expires_at ON api_keys(expires_at);
CREATE INDEX idx_api_keys_is_active ON api_keys(is_active);
CREATE INDEX idx_api_keys_last_used_at ON api_keys(last_used_at);
```
### **Migration Script:**
```bash
php run_hardening_migration.php
```
**Note:** Script akan otomatis skip jika column/index sudah ada.
---
## 🔧 IMPLEMENTATION DETAILS
### **1. Rate Limiting**
**Storage:**
- File-based cache di `storage/cache/rate_limit/`
- Format: JSON file per API key
- Auto cleanup saat window expired
**Algorithm:**
- Sliding window per API key
- Counter reset setiap window seconds
- Thread-safe dengan file locking
**Upgrade Path:**
- Bisa upgrade ke Redis/Memcached nanti
- Interface sudah abstract, cukup ganti storage layer
### **2. IP Whitelist**
**Validation:**
- Check exact match untuk single IP
- Check CIDR range untuk subnet
- Support IPv4 (IPv6 bisa ditambahkan nanti)
**Performance:**
- Cached di memory per request
- No database query jika disabled
### **3. API Key Expiration**
**Validation:**
- Check saat API key validation
- Compare dengan current timestamp
- Log expired attempts
### **4. Request Timestamp**
**Validation:**
- Optional (tidak block by default)
- Max age: 5 minutes
- Prevent replay attack
---
## 🛡️ SECURITY FLOW
```
Request → ApiKeyMiddleware
1. Extract X-Client-ID & X-Client-Secret
2. Validate API Key (database)
3. ✅ Check Expiration (if column exists)
4. ✅ Check IP Whitelist (if enabled)
5. ✅ Check Rate Limit (always enabled)
6. ✅ Validate Timestamp (optional, log only)
7. Attach API Key to Request
8. Add Rate Limit Headers to Response
Response
```
---
## 📝 USAGE EXAMPLES
### **Example 1: Basic API Call (No Hardening Config)**
```http
POST /fast/check_bill
X-Client-ID: ABC_1234567890_abcdef
X-Client-Secret: 64_char_hex_string
Response:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1705123456
```
### **Example 2: Rate Limit Exceeded**
```http
POST /fast/check_bill
X-Client-ID: ABC_1234567890_abcdef
X-Client-Secret: 64_char_hex_string
Response:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705123456
Retry-After: 45
{
"status": "error",
"message": "Rate limit exceeded. Please try again later.",
"retry_after": 45
}
```
### **Example 3: IP Not Whitelisted**
```http
POST /fast/check_bill
X-Client-ID: ABC_1234567890_abcdef
X-Client-Secret: 64_char_hex_string
IP: 192.168.1.200 (not in whitelist)
Response:
HTTP/1.1 403 Forbidden
{
"status": "error",
"message": "IP address not allowed"
}
```
### **Example 4: API Key Expired**
```http
POST /fast/check_bill
X-Client-ID: ABC_1234567890_abcdef
X-Client-Secret: 64_char_hex_string
Response:
HTTP/1.1 401 Unauthorized
{
"status": "error",
"message": "API key has expired"
}
```
---
## ⚙️ CONFIGURATION
### **Environment Variables (Optional):**
```env
# Rate Limiting (defaults)
RATE_LIMIT_DEFAULT=100
RATE_LIMIT_WINDOW=60
# Timestamp Validation (defaults)
TIMESTAMP_MAX_AGE=300
```
### **Database Configuration:**
```sql
-- Set custom rate limit
UPDATE api_keys
SET rate_limit_per_minute = 200,
rate_limit_window = 60
WHERE id = 1;
-- Enable IP whitelist
UPDATE api_keys
SET enable_ip_whitelist = 1,
ip_whitelist = '192.168.1.100,10.0.0.0/24'
WHERE id = 1;
-- Set expiration
UPDATE api_keys
SET expires_at = '2025-12-31 23:59:59'
WHERE id = 1;
```
---
## 🔍 MONITORING & LOGGING
### **API Logs:**
Semua hardening events di-log ke `api_logs` table:
```sql
-- View rate limit events
SELECT * FROM api_logs
WHERE status = 'rate_limited'
ORDER BY created_at DESC;
-- View IP blocked events
SELECT * FROM api_logs
WHERE status = 'ip_blocked'
ORDER BY created_at DESC;
-- View expired API keys
SELECT * FROM api_logs
WHERE status = 'expired'
ORDER BY created_at DESC;
```
### **Rate Limit Cache Files:**
```bash
# View rate limit cache
ls -la storage/cache/rate_limit/
# Clear rate limit cache (emergency)
rm -rf storage/cache/rate_limit/*
```
---
## ✅ BACKWARD COMPATIBILITY
**Semua hardening features adalah backward compatible:**
1.**Rate Limiting** - Always enabled, default 100 req/min
2.**IP Whitelist** - Default disabled (allow all IPs)
3.**Expiration** - Default never expires (NULL)
4.**Timestamp** - Optional, tidak block by default
**Jika column belum ada di database:**
- Hardening features akan **skip gracefully**
- Error di-log tapi request tetap di-allow (fail open)
- Tidak ada breaking changes untuk existing API keys
---
## 🚀 UPGRADE PATH
### **Future Enhancements:**
1. **Redis/Memcached untuk Rate Limiting**
- Ganti file-based cache dengan Redis
- Better performance untuk high traffic
2. **Advanced Rate Limiting**
- Per-endpoint rate limiting
- Burst protection
- Adaptive rate limiting
3. **Request Signature (HMAC)**
- HMAC SHA256 signature validation
- Prevent request tampering
- Replay attack protection
4. **API Key Rotation**
- Automatic key rotation
- Grace period untuk old keys
- Notification sebelum expiration
---
## 📋 CHECKLIST
- ✅ Rate Limiting implemented
- ✅ IP Whitelist implemented
- ✅ API Key Expiration implemented
- ✅ Request Timestamp validation implemented
- ✅ Database migration script created
- ✅ Backward compatible (fail open)
- ✅ Error handling & logging
- ✅ Response headers added
- ✅ Documentation created
---
**Status:** ✅ **HARDENING COMPLETED**
**Level Security:** **ENHANCED** (dari basic ke hardened)
**Production Ready:** ✅ **YES** (backward compatible)