Separate Keys by Environment
Security & Fraud Prevention
Security & Fraud Prevention
SanPay is built with security at its core. From HMAC-signed webhooks to origin validation, we protect every transaction and integration point.
API Key Security
Your API keys are the gateway to your account. Follow these best practices:
Never Expose Secret Keys
Rotate Keys Regularly
Use Environment Variables
Key Types
| Key Type | Prefix | Usage |
|---|---|---|
| Public Key | pk_live_* / pk_test_* | Client-side SDK initialization |
| Secret Key | sk_live_* / sk_test_* | Server-to-server API calls |
| Webhook Secret | whsec_* | Verify incoming webhook signatures |
Webhook Signature Verification
Every webhook includes an HMAC-SHA256 signature to verify authenticity and prevent tampering.
Signature Format
The `X-Webhook-Signature` header contains:
t=1704556800000,v1=a1b2c3d4e5f6... Verification Algorithm
- Extract timestamp (t) and signature (v1) from header
- Check timestamp is within acceptable window (5 minutes)
- Compute expected: HMAC-SHA256(secret, "{timestamp}.{body}")
- Use timing-safe comparison to verify signature
// PHP Signature Verification$payload = file_get_contents('php://input');$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
// Parse signaturepreg_match('/^t=(\d+),v1=([a-f0-9]+)$/', $signature, $matches);$timestamp = (int) $matches[1];$receivedHash = $matches[2];
// Check timestamp (5 minute tolerance)$now = (int) (microtime(true) * 1000);if (abs($now - $timestamp) > 300000) { throw new Exception('Signature expired');}
// Verify signature$signedPayload = "{$timestamp}.{$payload}";$expectedHash = hash_hmac('sha256', $signedPayload, $webhookSecret);
if (!hash_equals($expectedHash, $receivedHash)) { throw new Exception('Invalid signature');}Why Timing-Safe Comparison?
Standard string comparison can leak information through response timing. Attackers could deduce the signature character-by-character. Timing-safe comparison takes constant time regardless of match position.
Origin Validation
The SDK validates that requests come from authorized domains:
- Configure allowed origins in your SanPay dashboard
- Include protocol, domain, and port: https://example.com:443
- Use wildcards carefully: https://*.example.com
Replay Attack Protection
Webhooks include timestamps to prevent replay attacks:
- Reject signatures older than 5 minutes
- Store processed eventIds to detect duplicates
- All communication over HTTPS prevents interception
Rate Limiting
API endpoints are rate-limited to prevent abuse:
| Endpoint | Limit | Window |
|---|---|---|
| Payment creation | 100 req | per minute |
| Status checks | 300 req | per minute |
| Asset listing | 60 req | per minute |
Security Best Practices
Always Verify Webhooks
Use Idempotency
Validate Amounts
HTTPS Only