Essentials

Security Best Practices

Secure your DVPay API integration and protect sensitive data

Security is critical when integrating payment systems. This guide covers best practices for securing your DVPay API integration, protecting customer data, and preventing common security vulnerabilities.

API Credential Security

Store Credentials Securely

Never hardcode API credentials in your source code or commit them to version control.

✅ Do: Use Environment Variables

# Store credentials in environment variables
DVPAY_APP_ID=your_app_id_here
DVPAY_API_KEY=your_api_key_here
DVPAY_WEBHOOK_SECRET=your_webhook_secret_here

# Never commit .env to git
# Add to .gitignore

❌ Don't: Hardcode Credentials

// NEVER DO THIS!
const apiKey = 'sk_live_abc123xyz789'; // Exposed in code
const appId = 'app_456def'; // Version control leak risk

Credential Rotation

Rotate API keys regularly to minimize exposure risk:

Generate New Credentials

In DVPay merchant dashboard: API SettingsRegenerate Keys

Update Environment Variables

# Update production environment
export DVPAY_API_KEY=new_key_value

Deploy Updated Configuration

Redeploy your application with new credentials

Revoke Old Credentials

In DVPay dashboard: API SettingsRevoke Old Keys

Rotate credentials immediately if you suspect they've been compromised.

HTTPS & Transport Security

Always Use HTTPS

Never send API requests over unencrypted HTTP connections.

✅ Correct:

const baseURL = 'https://merchant.dv.vai247.pro/api/v1'; // HTTPS

❌ Wrong:

const baseURL = 'http://merchant.dv.vai247.pro/api/v1'; // HTTP (insecure!)

Verify SSL Certificates

Ensure your HTTP client validates SSL certificates:

import (
    "crypto/tls"
    "net/http"
)

func createSecureClient() *http.Client {
    return &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{
                MinVersion: tls.VersionTLS12, // Enforce TLS 1.2+
                // InsecureSkipVerify: false, // NEVER set to true in production
            },
        },
    }
}

Webhook Security

Verify Webhook Signatures

Always validate that webhooks are sent by DVPay:

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func verifyWebhookSignature(payload []byte, signature string, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(payload)
    expectedSignature := hex.EncodeToString(mac.Sum(nil))

    return hmac.Equal([]byte(signature), []byte(expectedSignature))
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    signature := r.Header.Get("X-DVPay-Signature")
    webhookSecret := os.Getenv("DVPAY_WEBHOOK_SECRET")

    if !verifyWebhookSignature(body, signature, webhookSecret) {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }

    // Process webhook...
}

Use HTTPS Webhook Endpoints

# ✅ Correct
https://yourdomain.com/webhooks/dvpay

# ❌ Wrong
http://yourdomain.com/webhooks/dvpay

DVPay will reject HTTP webhook URLs in production.

Request Validation

Validate Timestamp Headers

Prevent replay attacks by validating timestamps:

func validateTimestamp(timestamp string) error {
    ts, err := strconv.ParseInt(timestamp, 10, 64)
    if err != nil {
        return errors.New("invalid timestamp format")
    }

    now := time.Now().Unix()
    diff := now - ts

    // Allow ±5 minutes tolerance
    if diff > 300 || diff < -300 {
        return errors.New("timestamp expired")
    }

    return nil
}

func makeAPIRequest(url string, payload interface{}) error {
    timestamp := fmt.Sprintf("%d", time.Now().Unix())

    if err := validateTimestamp(timestamp); err != nil {
        return err
    }

    req.Header.Set("X-Timestamp", timestamp)
    // Continue with request...
}

Sanitize User Input

Always validate and sanitize user-provided data:

import (
    "errors"
    "regexp"
)

func validateOrderRequest(req CreateOrderRequest) error {
    // Validate amount
    if req.Amount <= 0 {
        return errors.New("amount must be positive")
    }
    if req.Amount > 10000 {
        return errors.New("amount exceeds maximum")
    }

    // Validate currency
    validCurrencies := map[string]bool{"USD": true, "KHR": true}
    if !validCurrencies[req.Currency] {
        return errors.New("invalid currency")
    }

    // Validate store ID format
    matched, _ := regexp.MatchString(`^[a-zA-Z0-9_-]+$`, req.StoreID)
    if !matched {
        return errors.New("invalid store_id format")
    }

    return nil
}

Data Protection

Minimize Data Exposure

Only log necessary information and never log sensitive data:

✅ Safe Logging:

logger.info('Order created', {
  order_id: order.id,
  amount: order.amount,
  currency: order.currency,
  timestamp: Date.now()
});

❌ Unsafe Logging:

// NEVER log sensitive data!
logger.info('Request sent', {
  api_key: config.apiKey, // ❌ Exposed credential
  customer_phone: customer.phone, // ❌ PII
  full_request: request // ❌ May contain secrets
});

Mask Sensitive Data

When displaying data to users or in logs:

function maskApiKey(apiKey) {
  return apiKey.substring(0, 8) + '****' + apiKey.substring(apiKey.length - 4);
}

console.log(`Using API key: ${maskApiKey(config.apiKey)}`);
// Output: Using API key: sk_live_****xyz9

Rate Limiting & Abuse Prevention

Implement Client-Side Rate Limiting

Prevent hitting API rate limits:

import (
    "sync"
    "time"
)

type RateLimiter struct {
    requests int
    limit    int
    window   time.Duration
    mu       sync.Mutex
    reset    time.Time
}

func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
    return &RateLimiter{
        limit:  limit,
        window: window,
        reset:  time.Now().Add(window),
    }
}

func (rl *RateLimiter) Allow() bool {
    rl.mu.Lock()
    defer rl.mu.Unlock()

    now := time.Now()
    if now.After(rl.reset) {
        rl.requests = 0
        rl.reset = now.Add(rl.window)
    }

    if rl.requests >= rl.limit {
        return false
    }

    rl.requests++
    return true
}

// Usage
limiter := NewRateLimiter(100, time.Minute)

if !limiter.Allow() {
    return errors.New("rate limit exceeded")
}

Implement Idempotency

Prevent duplicate operations:

const { v4: uuidv4 } = require('uuid');

// Store idempotency key with request
const idempotencyKey = uuidv4();

await axios.post(url, orderData, {
  headers: {
    ...authHeaders,
    'X-Idempotency-Key': idempotencyKey
  }
});

// Same key returns same result if retried

IP Whitelisting

Restrict API access to known IP addresses:

Get Your Server IPs

curl ifconfig.me
# Output: 203.0.113.10

Configure in DVPay Dashboard

API SettingsIP Whitelist → Add your server IPs

Test Access

Requests from non-whitelisted IPs will return 403 Forbidden

IP whitelisting is optional but recommended for high-security environments.

Dependency Security

Keep Dependencies Updated

Regularly update packages to patch vulnerabilities:

# Check for vulnerabilities
npm audit

# Update dependencies
npm update

# For critical vulnerabilities
npm audit fix

Use Dependency Scanning

Add security scanning to your CI/CD pipeline:

# .github/workflows/security.yml
name: Security Scan

on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run npm audit
        run: npm audit --audit-level=moderate

Error Handling Security

Don't Expose Internal Details

✅ Safe Error Response:

catch (error) {
  res.status(500).json({
    error: 'An error occurred processing your request',
    request_id: error.request_id
  });

  // Log full details internally
  logger.error('Internal error', { error, stack: error.stack });
}

❌ Unsafe Error Response:

catch (error) {
  // ❌ Exposes internal details
  res.status(500).json({
    error: error.message,
    stack: error.stack, // ❌ Reveals code structure
    config: config // ❌ May contain secrets
  });
}

Security Checklist

Before going to production:

Credentials

  • API keys stored in environment variables
  • Credentials not committed to version control
  • Separate sandbox and production credentials
  • Credential rotation schedule established

Transport Security

  • All requests use HTTPS
  • SSL certificate validation enabled
  • TLS 1.2+ enforced

Webhook Security

  • Webhook signature verification implemented
  • HTTPS webhook endpoint configured
  • Idempotent webhook processing

Validation

  • Timestamp validation implemented
  • User input sanitized
  • Request/response validation

Data Protection

  • Sensitive data not logged
  • API keys masked in logs
  • PII handling compliant with regulations

Rate Limiting

  • Client-side rate limiting implemented
  • Retry logic with exponential backoff
  • Idempotency keys used for operations

Monitoring

  • Error logging with request IDs
  • Security alerts configured
  • Failed authentication monitoring

Compliance Considerations

PCI DSS Compliance

DVPay handles payment processing, but you must:

  • Never store card numbers, CVV, or full track data
  • Use HTTPS for all payment-related pages
  • Maintain security logs and monitoring
  • Implement proper access controls

GDPR & Data Privacy

When handling customer data:

  • Collect only necessary information
  • Store data securely
  • Provide data deletion capabilities
  • Maintain data processing records
Consult legal counsel to ensure compliance with applicable regulations in your jurisdiction.

Incident Response

If credentials are compromised:

Immediately Revoke

Revoke compromised API keys in DVPay dashboard

Generate New Credentials

Create new API keys immediately

Update Applications

Deploy updated credentials to all services

Audit Logs

Review access logs for suspicious activity

Notify Stakeholders

Inform relevant parties of the incident

Next Steps

Currencies & Conversion

Learn about multi-currency support and conversion

Order Lifecycle

Understand payment order states and transitions