Webhook Security
Properly securing your webhook endpoints is critical to prevent unauthorized access and data tampering.
Secret Verification
Every webhook request includes an X-Webhook-Secret header containing your unique webhook secret. Always verify this header before processing the request.
How It Works
- When you create a webhook, PDF-Sign generates a unique secret (format:
whsec_...) - This secret is included in the
X-Webhook-Secretheader of every request - Your endpoint should verify the secret matches before processing
Example Verification
// Node.js / Express
app.post('/webhooks/pdf-sign', (req, res) => {
const receivedSecret = req.headers['x-webhook-secret'];
const expectedSecret = process.env.PDF_SIGN_WEBHOOK_SECRET;
if (receivedSecret !== expectedSecret) {
console.error('Invalid webhook secret');
return res.status(401).json({ error: 'Unauthorized' });
}
// Process the webhook...
res.status(200).json({ received: true });
});
# Python / Flask
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
@app.route('/webhooks/pdf-sign', methods=['POST'])
def handle_webhook():
received_secret = request.headers.get('X-Webhook-Secret')
expected_secret = os.environ.get('PDF_SIGN_WEBHOOK_SECRET')
if received_secret != expected_secret:
return jsonify({'error': 'Unauthorized'}), 401
# Process the webhook...
return jsonify({'received': True}), 200
Never Skip Verification
Without secret verification, anyone who discovers your endpoint URL could send fake webhook requests.
Secure Your Secret
Do's
- Store in environment variables - Never hardcode secrets
- Use secret management - Consider using AWS Secrets Manager, HashiCorp Vault, etc.
- Rotate periodically - Create new webhooks and delete old ones regularly
- Limit access - Only give secret access to services that need it
Don'ts
- Never commit to source control - Add
.envto.gitignore - Never log the secret - Avoid printing secrets in logs
- Never expose in client-side code - Secrets are for server-side only
- Never share via insecure channels - Don't send secrets in plain email/chat
HTTPS Requirement
PDF-Sign only sends webhooks to HTTPS endpoints. This ensures:
- Encryption in transit - Data cannot be intercepted
- Server authentication - You know you're sending to the right server
- Data integrity - Payloads cannot be tampered with
Development Testing
For local development, use tools like ngrok or localtunnel to create an HTTPS tunnel to your local server.
Additional Headers
Use additional headers for extra verification:
| Header | Purpose |
|---|---|
X-Webhook-Event | Verify the event type matches expected |
X-Webhook-Timestamp | Check request freshness (reject old requests) |
User-Agent | Verify it's PDF-Sign-Webhook/1.0 |
Timestamp Verification
Prevent replay attacks by rejecting old requests:
const timestamp = parseInt(req.headers['x-webhook-timestamp']);
const now = Date.now();
const fiveMinutes = 5 * 60 * 1000;
if (Math.abs(now - timestamp) > fiveMinutes) {
return res.status(400).json({ error: 'Request too old' });
}
IP Allowlisting
For additional security, you can restrict your endpoint to only accept requests from PDF-Sign's servers. Contact support for the current IP ranges.
Dynamic IPs
Our IP ranges may change. Subscribe to our status page for notifications about infrastructure changes.
Error Handling
Handle errors gracefully without exposing internal details:
app.post('/webhooks/pdf-sign', (req, res) => {
try {
// Verify and process...
} catch (error) {
// Log internally
console.error('Webhook processing error:', error);
// Return generic error (don't expose details)
res.status(500).json({ error: 'Internal error' });
}
});
Rate Limiting
Protect your endpoint from abuse with rate limiting:
const rateLimit = require('express-rate-limit');
const webhookLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 100, // Max 100 requests per minute
message: { error: 'Too many requests' }
});
app.post('/webhooks/pdf-sign', webhookLimiter, (req, res) => {
// Handle webhook...
});
Security Checklist
Before going to production, ensure:
- Secret verification is implemented
- Secret is stored in environment variables
- Endpoint uses HTTPS
- Timestamp verification (optional but recommended)
- Error handling doesn't expose internals
- Rate limiting is configured
- Logging doesn't include sensitive data
- Access to webhook secret is restricted
Reporting Security Issues
If you discover a security vulnerability in PDF-Sign's webhook system, please report it responsibly to security@pdf-sign.com. We take all reports seriously and will respond promptly.