Add two layers of defense:
1. Webhook availability guard (controller/payment_webhook_availability.go):
- isStripeWebhookEnabled() checks StripeWebhookSecret != "" before processing
- isCreemWebhookEnabled(), isWechatPayWebhookEnabled(), isAlipayWebhookEnabled()
- isEpayWebhookEnabled() with similar checks for all payment webhooks
- Applied to: StripeWebhook, CreemWebhook, WechatPayWebhook, AlipayPayWebhook,
EpayNotify, SubscriptionEpayNotify
2. PaymentProvider field (model/topup.go):
- New PaymentProvider field on TopUp to identify which gateway created the order
- Recharge() checks PaymentProvider == PaymentProviderStripe
- rechargeByQRCodePayment() checks PaymentProvider matches wechat/alipay
- RechargeCreem() checks PaymentProvider == PaymentProviderCreem
- All payment controllers set PaymentProvider when creating orders
Root cause: When StripeWebhookSecret was empty, ComputeSignature used
an empty HMAC key, allowing attackers to forge valid signatures and
complete orders from any payment gateway without actually paying.
Co-Authored-By: Claude <noreply@anthropic.com>