Skip to main content

Webhook Security

Securing your webhook endpoints is critical to protecting your application from unauthorized access, data tampering, and malicious attacks. This guide provides comprehensive security practices for implementing and maintaining secure webhook integrations with Dasha BlackBox.

Overview

Webhook security involves multiple layers of protection to ensure that:
  • Only legitimate Dasha BlackBox webhooks reach your application
  • Webhook payloads haven’t been tampered with during transmission
  • Replay attacks are prevented
  • Sensitive data is protected in transit and at rest
  • Your webhook endpoint can’t be overwhelmed by malicious traffic
Security is not optional: Failing to properly secure webhook endpoints can lead to data breaches, service disruptions, unauthorized access, and compliance violations. Treat webhook security with the same rigor as user authentication.

Why Webhook Security Matters

Webhooks are publicly accessible endpoints that accept data from external sources. Without proper security measures, your application is vulnerable to:

Spoofing Attacks

Malicious actors can send fake webhook requests pretending to be from Dasha BlackBox, potentially:
  • Injecting false data into your systems
  • Triggering unauthorized actions
  • Bypassing business logic validation
  • Corrupting analytics and reporting

Tampering Attacks

Without integrity verification, attackers can:
  • Modify webhook payload data in transit
  • Change call outcomes or transcripts
  • Manipulate financial or user data
  • Alter system state maliciously

Replay Attacks

Captured legitimate webhook requests can be:
  • Resent multiple times to duplicate actions
  • Used to overwhelm your systems
  • Exploited to trigger unintended side effects
  • Leveraged to bypass rate limiting

Data Exposure

Insecure webhook endpoints can:
  • Expose sensitive call data over unencrypted connections
  • Leak personally identifiable information (PII)
  • Violate GDPR, HIPAA, or other compliance requirements
  • Compromise user privacy

HTTPS Requirement

All webhook endpoints MUST use HTTPS with valid TLS/SSL certificates. HTTP is not supported and will be rejected by Dasha BlackBox.

Why HTTPS is Required

Encryption in Transit
  • Prevents eavesdropping on webhook payloads
  • Protects sensitive call data (transcripts, user info, metadata)
  • Ensures data integrity during transmission
  • Meets compliance requirements (PCI DSS, HIPAA, GDPR)
Server Authentication
  • Validates your server’s identity via SSL certificates
  • Prevents man-in-the-middle attacks
  • Ensures webhooks reach the intended destination
  • Provides chain of trust verification

SSL Certificate Requirements

Required for Production:
  • Valid SSL certificate from trusted Certificate Authority (CA)
  • Certificate not expired or self-signed
  • Certificate matches your domain exactly
  • TLS 1.2 or higher (TLS 1.3 recommended)
  • Strong cipher suites enabled
  • No mixed content (all resources over HTTPS)
Recommended Certificate Authorities:
  • Let’s Encrypt (free, automated renewal)
  • DigiCert
  • Sectigo
  • GlobalSign
  • AWS Certificate Manager (for AWS-hosted endpoints)
Automated Certificate Management: Use Let’s Encrypt with automated renewal (Certbot) to eliminate manual certificate management and prevent expiration issues.

Webhook Signatures

Dasha BlackBox signs all webhook requests using HMAC-SHA256 to ensure authenticity and integrity. Always verify webhook signatures before processing payloads.

How Webhook Signatures Work

  1. Dasha BlackBox generates signature:
    • Creates HMAC-SHA256 hash of webhook payload
    • Uses your secret key as the signing key
    • Includes signature in X-Dasha BlackBox-Signature header
  2. Your server verifies signature:
    • Receives webhook with signature header
    • Computes HMAC-SHA256 of received payload with same secret
    • Compares computed signature with received signature
    • Accepts webhook only if signatures match

Signature Verification Algorithm

1

Extract Signature from Header

const receivedSignature = request.headers['x-blackbox-signature'];

if (!receivedSignature) {
  // Reject unsigned requests
  return res.status(401).json({ error: 'Missing signature' });
}
2

Get Raw Request Body

// CRITICAL: Use raw request body, not parsed JSON
// Signature is computed from exact bytes received

const rawBody = request.rawBody; // Express: use raw-body middleware
// or
const rawBody = await request.text(); // Next.js/modern frameworks
3

Compute HMAC-SHA256 Hash

const crypto = require('crypto');

const secret = process.env.BLACKBOX_WEBHOOK_SECRET;

const computedSignature = crypto
  .createHmac('sha256', secret)
  .update(rawBody)
  .digest('hex');
4

Compare Signatures Securely

// Use timing-safe comparison to prevent timing attacks
const crypto = require('crypto');

const isValid = crypto.timingSafeEqual(
  Buffer.from(receivedSignature, 'hex'),
  Buffer.from(computedSignature, 'hex')
);

if (!isValid) {
  return res.status(401).json({ error: 'Invalid signature' });
}
5

Process Webhook Payload

// Signature verified - safe to process
const payload = JSON.parse(rawBody);

await processWebhook(payload);

return res.status(200).json({ success: true });

Complete Signature Verification Examples

const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');

const app = express();

// CRITICAL: Use raw body for signature verification
app.use(bodyParser.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

app.post('/webhooks/blackbox', async (req, res) => {
  try {
    // Step 1: Extract signature header
    const receivedSignature = req.headers['x-blackbox-signature'];

    if (!receivedSignature) {
      console.error('Missing webhook signature');
      return res.status(401).json({ error: 'Unauthorized' });
    }

    // Step 2: Get raw request body
    const rawBody = req.rawBody;

    if (!rawBody) {
      console.error('Missing request body');
      return res.status(400).json({ error: 'Bad Request' });
    }

    // Step 3: Compute expected signature
    const secret = process.env.BLACKBOX_WEBHOOK_SECRET;

    const computedSignature = crypto
      .createHmac('sha256', secret)
      .update(rawBody)
      .digest('hex');

    // Step 4: Timing-safe comparison
    const signatureBuffer = Buffer.from(receivedSignature, 'hex');
    const computedBuffer = Buffer.from(computedSignature, 'hex');

    if (signatureBuffer.length !== computedBuffer.length) {
      console.error('Signature length mismatch');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    const isValid = crypto.timingSafeEqual(signatureBuffer, computedBuffer);

    if (!isValid) {
      console.error('Signature verification failed');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Step 5: Process webhook (signature verified)
    const payload = JSON.parse(rawBody);

    console.log('Webhook verified:', payload.event);

    // Process webhook based on event type
    await handleWebhookEvent(payload);

    return res.status(200).json({ success: true });

  } catch (error) {
    console.error('Webhook processing error:', error);
    return res.status(500).json({ error: 'Internal server error' });
  }
});

async function handleWebhookEvent(payload) {
  switch (payload.type) {
    case 'StartWebHookPayload':
      await handleCallStarted(payload);
      break;
    case 'CompletedWebHookPayload':
      await handleCallCompleted(payload);
      break;
    case 'FailedWebHookPayload':
      await handleCallFailed(payload);
      break;
    default:
      console.warn('Unknown payload type:', payload.type);
  }
}

app.listen(3000, () => {
  console.log('Webhook endpoint listening on port 3000');
});
Common Mistakes to Avoid:
  • Using parsed JSON body: Signature must be computed from raw bytes, not re-serialized JSON
  • String comparison: Use timing-safe comparison to prevent timing attacks
  • Wrong secret: Ensure secret matches what’s configured in Dasha BlackBox dashboard
  • Missing middleware: Some frameworks parse body before signature verification runs
  • Character encoding: Ensure consistent UTF-8 encoding throughout

Timestamp Validation

Prevent replay attacks by validating webhook timestamps. Reject webhooks that are too old to prevent attackers from reusing captured requests.

Why Timestamp Validation Matters

Replay Attack Prevention
  • Captured legitimate webhooks can’t be resent hours/days later
  • Limits the window of opportunity for attackers
  • Prevents duplicate processing of old events
  • Protects against time-based manipulation
Clock Skew Tolerance
  • Accounts for small time differences between servers
  • Typical tolerance: 5 minutes (300 seconds)
  • Prevents false rejections due to network latency

Implementation Guide

function validateWebhookTimestamp(payload) {
  const TOLERANCE_SECONDS = 300; // 5 minutes

  // Extract timestamp from payload
  const webhookTimestamp = new Date(payload.timestamp);
  const currentTimestamp = new Date();

  // Calculate age of webhook
  const ageSeconds = (currentTimestamp - webhookTimestamp) / 1000;

  // Reject if too old
  if (ageSeconds > TOLERANCE_SECONDS) {
    console.error(`Webhook too old: ${ageSeconds}s (max ${TOLERANCE_SECONDS}s)`);
    return false;
  }

  // Reject if from future (clock skew)
  if (ageSeconds < -TOLERANCE_SECONDS) {
    console.error(`Webhook from future: ${ageSeconds}s`);
    return false;
  }

  return true;
}

// In your webhook handler:
app.post('/webhooks/blackbox', async (req, res) => {
  // ... signature verification ...

  const payload = JSON.parse(req.rawBody);

  // Validate timestamp
  if (!validateWebhookTimestamp(payload)) {
    return res.status(401).json({ error: 'Webhook timestamp invalid or expired' });
  }

  // Process webhook
  await handleWebhookEvent(payload);

  return res.status(200).json({ success: true });
});
Adjusting Tolerance: If you experience legitimate webhook rejections due to clock skew, you can increase the tolerance to 10 minutes (600 seconds), but never exceed 15 minutes for security reasons.

IP Whitelisting

Restrict webhook delivery to known Dasha BlackBox IP ranges for additional security.

Dasha BlackBox Webhook IP Ranges

Configure your firewall or application to only accept webhook requests from these IP ranges:
Production IP Ranges (CIDR notation):
- 52.202.195.162/32
- 34.226.14.86/32
- 3.218.180.13/32

Development/Staging IP Ranges:
- 54.210.32.45/32
- 18.206.107.29/32
IP Ranges May Change: Dasha BlackBox IP ranges may be updated occasionally. Subscribe to the Dasha BlackBox Status Page for notifications about infrastructure changes.

Implementation by Platform

# Add inbound rules to security group
aws ec2 authorize-security-group-ingress \
  --group-id sg-12345678 \
  --protocol tcp \
  --port 443 \
  --cidr 52.202.195.162/32

aws ec2 authorize-security-group-ingress \
  --group-id sg-12345678 \
  --protocol tcp \
  --port 443 \
  --cidr 34.226.14.86/32

aws ec2 authorize-security-group-ingress \
  --group-id sg-12345678 \
  --protocol tcp \
  --port 443 \
  --cidr 3.218.180.13/32
Behind a Proxy? If your application is behind a reverse proxy (Nginx, Cloudflare, AWS ALB), use the X-Forwarded-For header to get the real client IP. Always validate the proxy is trusted before trusting this header.

Authentication Headers

In addition to signature verification, use custom authentication headers for defense-in-depth.

Custom Token Authentication

Include a secret token in webhook configuration that must be present in all requests.
In Dasha BlackBox Dashboard:
  1. Navigate to agent configuration
  2. Go to Webhooks tab
  3. Set webhook URL with authentication token:
https://api.yourapp.com/webhooks/blackbox?token=your_secret_token_here
Or use custom header (if supported):
URL: https://api.yourapp.com/webhooks/blackbox
Headers:
  X-Auth-Token: your_secret_token_here
Token Security:
  • Generate cryptographically random tokens (minimum 32 characters)
  • Store tokens securely (environment variables, secrets manager)
  • Rotate tokens periodically (every 90 days recommended)
  • Never commit tokens to version control
  • Use different tokens for different environments

Rate Limiting

Protect your webhook endpoint from abuse by implementing rate limiting.

Why Rate Limiting Matters

  • DoS Protection: Prevent denial-of-service attacks
  • Resource Management: Protect application resources
  • Cost Control: Prevent runaway processing costs
  • Fair Usage: Ensure system stability under load

Rate Limiting Strategies

const rateLimit = require('express-rate-limit');

// Configure rate limiter
const webhookLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute window
  max: 100, // Max 100 requests per window per IP
  message: 'Too many webhook requests, please try again later',
  standardHeaders: true, // Return rate limit info in headers
  legacyHeaders: false,
  // Custom key generator (use IP or other identifier)
  keyGenerator: (req) => {
    return req.headers['x-forwarded-for']?.split(',')[0]
      || req.connection.remoteAddress;
  },
  // Skip rate limiting for successful requests
  skipSuccessfulRequests: false,
  // Skip rate limiting for failed requests
  skipFailedRequests: false,
});

// Apply to webhook endpoint
app.post('/webhooks/blackbox', webhookLimiter, async (req, res) => {
  // ... webhook processing ...
});
Choosing Rate Limits: Set limits based on expected legitimate traffic plus safety margin. For most applications, 100-1000 requests per minute per IP is reasonable. Monitor actual traffic patterns and adjust accordingly.

Idempotency

Handle duplicate webhook deliveries gracefully to prevent unintended side effects.

Why Idempotency Matters

Dasha BlackBox may deliver the same webhook multiple times due to:
  • Network retries: Temporary connection failures
  • Timeout retries: Your endpoint didn’t respond quickly enough
  • System failures: Infrastructure issues during delivery
  • Manual retries: Support team testing or investigation
Without idempotency, duplicate deliveries can cause:
  • Duplicate charges or transactions
  • Multiple database inserts
  • Repeated notifications to users
  • Incorrect analytics or reporting

Idempotency Implementation

Idempotency Key TTL: Store idempotency keys for at least 24 hours to handle delayed retries. For critical financial transactions, consider 7-30 days retention.

Secret Management

Store webhook secrets securely to prevent unauthorized access.

Environment Variables (Basic)

# .env file (never commit to version control)
BLACKBOX_WEBHOOK_SECRET=your_webhook_secret_here
WEBHOOK_AUTH_TOKEN=your_custom_auth_token_here

# Load in application
require('dotenv').config();

const secret = process.env.BLACKBOX_WEBHOOK_SECRET;
const { SecretsManagerClient, GetSecretValueCommand } =
  require('@aws-sdk/client-secrets-manager');

const client = new SecretsManagerClient({ region: 'us-east-1' });

async function getWebhookSecret() {
  try {
    const command = new GetSecretValueCommand({
      SecretId: 'blackbox/webhook-secret'
    });

    const response = await client.send(command);

    if (response.SecretString) {
      const secrets = JSON.parse(response.SecretString);
      return secrets.WEBHOOK_SECRET;
    }

    throw new Error('Secret not found');
  } catch (error) {
    console.error('Error retrieving secret:', error);
    throw error;
  }
}

// Cache secret (refresh periodically)
let cachedSecret = null;
let secretLastFetched = null;
const SECRET_CACHE_TTL = 3600000; // 1 hour

async function getCachedWebhookSecret() {
  const now = Date.now();

  if (!cachedSecret || (now - secretLastFetched) > SECRET_CACHE_TTL) {
    cachedSecret = await getWebhookSecret();
    secretLastFetched = now;
  }

  return cachedSecret;
}

HashiCorp Vault (Enterprise)

const vault = require('node-vault')({
  apiVersion: 'v1',
  endpoint: 'https://vault.yourcompany.com',
  token: process.env.VAULT_TOKEN
});

async function getWebhookSecret() {
  try {
    const result = await vault.read('secret/data/blackbox/webhooks');
    return result.data.data.WEBHOOK_SECRET;
  } catch (error) {
    console.error('Vault error:', error);
    throw error;
  }
}
Secret Rotation: Implement automated secret rotation every 90 days. When rotating, support both old and new secrets for 24 hours to prevent downtime during transition.

Security Best Practices Checklist

Use this checklist to ensure your webhook security implementation is complete.

Critical Security Requirements

  • HTTPS only - All webhook endpoints use valid SSL certificates
  • Signature verification - HMAC-SHA256 signatures validated for every request
  • Timestamp validation - Webhooks older than 5 minutes rejected
  • Secret storage - Webhook secrets stored in environment variables or secrets manager
  • Error handling - Security errors logged without exposing sensitive details
  • Input validation - All webhook data validated before processing

Important Security Measures

  • IP whitelisting - Only Dasha BlackBox IPs allowed to reach webhook endpoints
  • Rate limiting - Protection against DoS attacks implemented
  • Idempotency - Duplicate webhook deliveries handled correctly
  • Authentication headers - Custom tokens verified for defense-in-depth
  • Secure logging - No sensitive data (secrets, PII) logged
  • Regular audits - Security configuration reviewed monthly
  • Monitoring - Webhook failures and security events monitored
  • Alerting - Notifications for suspicious activity or high error rates
  • Documentation - Security procedures documented for team
  • Testing - Security measures tested regularly
  • Incident response - Plan exists for handling security breaches

Common Security Mistakes

Avoid these frequent webhook security pitfalls.

Using HTTP Instead of HTTPS

Problem: Webhook data transmitted in plaintext, exposing sensitive information. Solution: Always use HTTPS with valid SSL certificates. Configure redirects from HTTP to HTTPS.
# Nginx redirect
server {
    listen 80;
    server_name api.yourapp.com;
    return 301 https://$server_name$request_uri;
}

Skipping Signature Verification

Problem: Accepting all webhook requests without verifying authenticity. Solution: Implement HMAC-SHA256 signature verification for every request. Reject unsigned or invalid requests.

Computing Signature from Parsed JSON

Problem: Re-serializing JSON changes byte representation, causing signature mismatch. Solution: Compute signature from raw request body bytes before parsing JSON.
// WRONG
const payload = req.body;
const signature = crypto.createHmac('sha256', secret)
  .update(JSON.stringify(payload)) // Don't do this!
  .digest('hex');

// CORRECT
const rawBody = req.rawBody; // Raw bytes
const signature = crypto.createHmac('sha256', secret)
  .update(rawBody) // Use raw body
  .digest('hex');

Using String Comparison for Signatures

Problem: Vulnerable to timing attacks that can leak signature information. Solution: Use timing-safe comparison functions.
// WRONG
if (receivedSignature === computedSignature) { }

// CORRECT
const isValid = crypto.timingSafeEqual(
  Buffer.from(receivedSignature, 'hex'),
  Buffer.from(computedSignature, 'hex')
);

Storing Secrets in Code

Problem: Secrets committed to version control or exposed in application code. Solution: Use environment variables or secrets management services.
// WRONG
const secret = 'hardcoded_secret_12345'; // Never do this!

// CORRECT
const secret = process.env.BLACKBOX_WEBHOOK_SECRET;

No Idempotency Handling

Problem: Duplicate webhooks cause duplicate actions (charges, emails, database inserts). Solution: Implement idempotency using database or cache-based deduplication.

Exposing Webhook URLs

Problem: Webhook URLs discoverable through public repositories, logs, or error messages. Solution:
  • Use non-obvious webhook paths
  • Never log full webhook URLs
  • Add authentication tokens to query parameters or headers
  • Review public repositories for exposed secrets

Insufficient Error Handling

Problem: Security errors expose internal details to attackers. Solution: Return generic error messages, log detailed errors securely.
// WRONG
return res.status(401).json({
  error: 'Signature mismatch',
  expected: computedSignature,  // Don't expose this!
  received: receivedSignature   // Don't expose this!
});

// CORRECT
console.error('Signature verification failed', {
  expected: computedSignature,
  received: receivedSignature
});
return res.status(401).json({ error: 'Unauthorized' });

Compliance Considerations

Ensure webhook security meets regulatory and compliance requirements.

GDPR (General Data Protection Regulation)

Applies to: EU users or businesses operating in EU Key Requirements:
  • Data Encryption: All webhook data encrypted in transit (HTTPS)
  • Data Minimization: Only collect necessary data in webhooks
  • Access Control: Restrict who can configure webhooks
  • Right to Erasure: Ability to delete webhook data on request
  • Data Processing Agreement: Ensure Dasha BlackBox has GDPR-compliant DPA
Implementation:
// Redact PII from webhook logs
function logWebhook(payload) {
  const sanitized = {
    ...payload,
    data: {
      ...payload.data,
      // Redact PII fields
      phoneNumber: '[REDACTED]',
      email: '[REDACTED]',
      transcript: '[REDACTED]'
    }
  };

  console.log('Webhook received:', sanitized);
}

HIPAA (Health Insurance Portability and Accountability Act)

Applies to: Healthcare applications handling PHI (Protected Health Information) Key Requirements:
  • Encryption: End-to-end encryption for PHI data
  • Access Logs: Audit logs of all webhook access
  • Business Associate Agreement (BAA): Signed agreement with Dasha BlackBox
  • Breach Notification: Plan for reporting security incidents
Implementation:
// Audit logging for HIPAA compliance
function auditWebhookAccess(payload, result) {
  const auditLog = {
    timestamp: new Date().toISOString(),
    event: 'webhook_received',
    source: 'blackbox',
    eventType: payload.event,
    callId: payload.data?.callId,
    result: result.success ? 'success' : 'failure',
    ipAddress: req.headers['x-forwarded-for'] || req.connection.remoteAddress
  };

  // Store in secure, append-only audit log
  await auditLogger.log(auditLog);
}

PCI DSS (Payment Card Industry Data Security Standard)

Applies to: Applications processing payment card data Key Requirements:
  • No PAN Storage: Never store full card numbers in webhook payloads
  • Encrypted Transmission: TLS 1.2+ for all webhook traffic
  • Access Control: Restrict webhook configuration to authorized personnel
  • Logging: Log all webhook access for forensic analysis
Implementation:
// Tokenize sensitive data before logging
function processPCIWebhook(payload) {
  if (payload.data.paymentMethod) {
    // Replace with token, never log full card number
    payload.data.paymentMethod = {
      type: payload.data.paymentMethod.type,
      last4: payload.data.paymentMethod.last4,
      token: payload.data.paymentMethod.token
    };
  }

  return payload;
}

CCPA (California Consumer Privacy Act)

Applies to: Businesses serving California residents Key Requirements:
  • Data Disclosure: Inform users about data collected via webhooks
  • Right to Delete: Ability to delete user data from webhook storage
  • Opt-Out: Allow users to opt out of data collection

Troubleshooting Security Issues

Common security-related webhook problems and solutions.

Signature Verification Failing

Symptoms: All webhooks rejected with “Invalid signature” error Common Causes:
  1. Wrong secret: Using incorrect webhook secret
  2. Character encoding: UTF-8 encoding mismatch
  3. Body parsing: Signature computed from parsed JSON instead of raw bytes
  4. Whitespace: Extra whitespace in secret or body
Debugging Steps:
// Enable detailed signature debugging
function debugSignatureVerification(req) {
  const receivedSignature = req.headers['x-blackbox-signature'];
  const rawBody = req.rawBody;
  const secret = process.env.BLACKBOX_WEBHOOK_SECRET;

  console.log('=== Signature Debug ===');
  console.log('Received signature:', receivedSignature);
  console.log('Raw body length:', rawBody.length);
  console.log('Raw body (first 100 chars):', rawBody.substring(0, 100));
  console.log('Secret length:', secret.length);
  console.log('Secret (first 10 chars):', secret.substring(0, 10));

  const computedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  console.log('Computed signature:', computedSignature);
  console.log('Signatures match:', receivedSignature === computedSignature);
  console.log('======================');
}
Solutions:
  • Verify secret matches Dasha BlackBox dashboard configuration
  • Ensure raw body middleware configured correctly
  • Check for whitespace or encoding issues
  • Test with Dasha BlackBox webhook test feature

Webhooks from Future or Past

Symptoms: Legitimate webhooks rejected due to timestamp validation Common Causes:
  1. Clock skew: Server clock incorrect
  2. Timezone issues: Timestamp parsing in wrong timezone
  3. Tolerance too strict: 5-minute window too narrow
Solutions:
// Diagnose timestamp issues
function debugTimestamp(payload) {
  const webhookTimestamp = new Date(payload.timestamp);
  const serverTimestamp = new Date();

  console.log('=== Timestamp Debug ===');
  console.log('Webhook timestamp:', payload.timestamp);
  console.log('Parsed webhook time:', webhookTimestamp.toISOString());
  console.log('Server time:', serverTimestamp.toISOString());
  console.log('Difference (seconds):',
    (serverTimestamp - webhookTimestamp) / 1000);
  console.log('Server timezone:',
    Intl.DateTimeFormat().resolvedOptions().timeZone);
  console.log('======================');
}
Fixes:
  • Sync server clock with NTP
  • Increase tolerance to 10-15 minutes if needed
  • Ensure timestamps parsed as UTC

IP Whitelist Blocking Legitimate Webhooks

Symptoms: Webhooks rejected with 403 Forbidden Common Causes:
  1. Outdated IP ranges: Dasha BlackBox IPs changed
  2. Proxy issues: Getting proxy IP instead of original IP
  3. IPv6 vs IPv4: IP format mismatch
Solutions:
// Debug IP detection
function debugIPDetection(req) {
  console.log('=== IP Debug ===');
  console.log('X-Forwarded-For:', req.headers['x-forwarded-for']);
  console.log('X-Real-IP:', req.headers['x-real-ip']);
  console.log('Remote Address:', req.connection.remoteAddress);
  console.log('Socket Address:', req.socket.remoteAddress);
  console.log('================');
}
Fixes:
  • Verify Dasha BlackBox IP ranges on status page
  • Check reverse proxy configuration
  • Use X-Forwarded-For if behind trusted proxy

Rate Limiting Blocking Legitimate Traffic

Symptoms: Webhooks rejected with 429 Too Many Requests Solutions:
  • Review rate limit thresholds
  • Whitelist Dasha BlackBox IPs from rate limiting
  • Increase limits for webhook endpoints specifically
  • Monitor actual traffic patterns and adjust

Security Monitoring and Alerts

Proactive monitoring catches security issues before they become critical.

Metrics to Monitor

Security Events:
  • Invalid signature attempts
  • Timestamp validation failures
  • IP whitelist rejections
  • Rate limit violations
  • Authentication failures
Performance Metrics:
  • Webhook processing time
  • Error rates by error type
  • Duplicate webhook rate
  • Storage usage for idempotency keys

Alert Configuration

const { CloudWatchClient, PutMetricDataCommand } =
  require('@aws-sdk/client-cloudwatch');

const cloudwatch = new CloudWatchClient({ region: 'us-east-1' });

async function trackSecurityEvent(eventType) {
  const params = {
    Namespace: 'Webhooks/Security',
    MetricData: [
      {
        MetricName: 'SecurityEvents',
        Dimensions: [
          {
            Name: 'EventType',
            Value: eventType
          }
        ],
        Value: 1,
        Unit: 'Count',
        Timestamp: new Date()
      }
    ]
  };

  await cloudwatch.send(new PutMetricDataCommand(params));
}

// Track security events
if (!isValidSignature) {
  await trackSecurityEvent('InvalidSignature');
}
Configure alerts for these security scenarios: Critical (Immediate Response):
  • Above 10 invalid signatures per minute
  • Above 5 IP whitelist violations per minute
  • Sudden spike in authentication failures (above 100% baseline)
Warning (Investigation Needed):
  • Above 5 timestamp validation failures per hour
  • Rate limit hits increasing trend
  • Idempotency key storage above 80% capacity
Informational (Monitor Trends):
  • Daily summary of security events
  • Weekly security metrics report
  • Monthly compliance audit summary

Next Steps

After implementing webhook security:

API Cross-Refs

Webhook security-related endpoints: