文章目录Resend邮件轰炸投毒Reputation Poisoning解决方案测试地址解决不了生产环境滥用项目应该怎么做1. 使用独立发送子域名2. 在调用 Resend 之前限流3. 注册接口加入 Turnstile4. 发送前进行低成本检查5. 接入 Resend Webhook6. 未验证账户不要立即获得完整资源7. 建立熔断机制推荐的最低实现附 问题的本质️ 防御方案多层次1️⃣ 发送前验证邮箱最有效2️⃣ 频率限制Rate Limiting3️⃣ 人机验证阻止自动化攻击4️⃣ 延迟发送 退信自动抑制5️⃣ 使用独立子域名发送验证邮件 防御层次总结 最低成本方案适合小项目Resend邮件轰炸投毒Reputation Poisoning解决方案Resend邮件轰炸投毒Reputation Poisoning是一个真实风险。Resend 官方甚至直接举了例子有人 DDoS 注册页面系统向大量一次性或不存在的地址发送验证邮件导致大量退信。因此 Resend 建议不要直接使用根域名发信而应使用专门的邮件子域名以便出现问题时隔离信誉影响。(Resend)Resend 要求账户退信率保持在4% 以下超过后可能暂停发送垃圾邮件投诉率要求低于0.08%。对于刚上线、邮件量较小的项目攻击者制造少量退信就可能把比例迅速拉高。(Resend)测试地址解决不了生产环境滥用这些地址bouncedresend.dev complainedresend.dev suppressedresend.dev只是让开发者测试退信处理逻辑时不必随意构造假邮箱。真实注册页面仍然必须自行防止攻击者输入random123456gmail.com nobodyexample-company.com victimgmail.com前两类可能产生退信第三类可能真的收到邮件然后把你标记为垃圾邮件。项目应该怎么做1. 使用独立发送子域名不要直接使用verifyyour-domain.com建议在 Resend 中单独验证一个邮件子域名例如auth.your-domain.com发件人为your-projectverifyauth.your-domain.com或者notifications.your-project.your-domain.comResend 明确建议使用子域名进行“信誉隔离”即使注册邮件流量被攻击也可以停用或替换该子域名而不是直接损害根域名。(Resend)这不能保证根域名完全不受关联影响但能显著缩小故障范围。2. 在调用 Resend 之前限流不要把 Resend 自带的 API 限流当作反滥用措施。Resend 当前默认限制是整个 Team 每秒 10 个 API 请求这只是平台容量限制并不能阻止攻击者消耗你的额度和信誉。(Resend)注册接口至少需要同时限制维度建议起始值同一邮箱60 秒内最多发送 1 次同一邮箱每小时最多 3 次同一邮箱每天最多 5 次同一 IP10 分钟最多注册 5 次同一 IP每天最多注册 20 次全站异常流量达到阈值后启用验证码或暂停发送数据应放在 Redis、Upstash Redis 等服务端存储中不能只依赖前端按钮倒计时。3. 注册接口加入 Turnstile你已经在使用 Cloudflare适合直接加入Cloudflare Turnstile用户提交注册 ↓ 服务端验证 Turnstile token ↓ 检查 IP / 邮箱限流 ↓ 检查邮箱格式和域名 ↓ 创建 pending 用户 ↓ 调用 Resend验证码必须由后端验证。前端隐藏按钮或者 JavaScript 冷却时间都可以被绕过。4. 发送前进行低成本检查可以在调用 Resend 之前检查邮箱格式是否合法 域名是否存在 域名是否有 MX 记录 是否为明显的一次性邮箱域名 邮箱是否已在本地退信黑名单但要注意abc123456gmail.com即使这个具体账户不存在gmail.com仍然具有合法 MX 记录。因此MX 检查只能过滤不存在的域名不能确定具体邮箱账户存在。第三方邮箱验证服务可以进一步评估邮箱是否可投递但也不是百分之百准确。Resend 官方也将第三方可投递性验证作为降低退信率的一种措施。(Resend)5. 接入 Resend Webhook至少处理email.bounced email.complained email.suppressed email.delivered收到永久退信后在自己的数据库中记录emailStatus:BOUNCEDcanSendEmail:falsebounceReason:recipient_not_found之后禁止继续向该邮箱发送验证码。Resend 本身会把发生硬退信或投诉的地址放入 Suppression List后续发送会被直接抑制以保护域名信誉但你的应用仍应同步保存状态避免继续创建无意义的发送请求。(Resend) Resend Webhook 可以实时通知应用发生退信和投诉。(Resend)6. 未验证账户不要立即获得完整资源推荐账户状态PENDING_EMAIL_VERIFICATION VERIFIED BOUNCED BLOCKED EXPIRED未验证用户不能创建正式任务不能抓取职位不能反复触发验证邮件24 小时或数天后清理邮箱发生硬退信后直接冻结该注册记录。7. 建立熔断机制例如监控最近 1560 分钟发送总数 硬退信数量 投诉数量 单一 IP 注册量 单一邮箱域名的异常数量当短时间退信率异常上升时停止自动发送 强制所有注册通过 Turnstile 限制高风险 IP 触发管理员告警不能等 Resend 把整个账户暂停后才处理。推荐的最低实现对你目前的 项目最低上线配置应当是独立邮件子域名 Cloudflare Turnstile Redis 多维限流 邮箱格式和 MX 检查 Resend bounce/complaint webhook 本地 suppression 状态 未验证账户过期清理其中最重要的是Turnstile、应用层限流、独立邮件子域名和 Webhook。仅仅验证邮箱格式无法抵御这种攻击。附恶意用户确实可以通过大量使用不存在的邮箱注册来投毒你的发送域名信誉。让我详细分析一下这个攻击面和防御方案。 问题的本质这种攻击叫做“邮件轰炸投毒”Reputation Poisoning攻击者 → 用大量虚假邮箱注册你的网站 → 你的系统自动发送验证邮件到这些不存在的地址 → 大量退信Hard Bounce → 邮件服务商认为你在发垃圾邮件 → 你的域名信誉下降 → 正常用户的邮件也进垃圾箱或被拒收Resend、SendGrid、SES 等服务都会追踪你的bounce rate退信率通常退信率 5%警告退信率 10%可能暂停你的发送权限️ 防御方案多层次1️⃣ 发送前验证邮箱最有效在发送验证邮件之前先检查邮箱是否真实存在// 使用邮箱验证 API如 Hunter.io、ZeroBounce、NeverBounceimport{verifyEmail}fromsome-email-validator;app.post(/register,async(req,res){const{email}req.body;// 第一层格式校验if(!isValidEmailFormat(email)){returnres.status(400).json({error:邮箱格式错误});}// 第二层检查一次性邮箱临时邮箱if(isDisposableEmail(email)){returnres.status(400).json({error:不支持临时邮箱});}// 第三层MX 记录检查域名是否能收邮件consthasMXawaitcheckMXRecord(email.split()[1]);if(!hasMX){returnres.status(400).json({error:该邮箱域名无法接收邮件});}// 第四层可选调用验证 API 检查邮箱是否真实存在constverificationawaitverifyEmail(email);// ZeroBounce / Hunter.ioif(verification.statusinvalid){returnres.status(400).json({error:该邮箱地址不存在});}// 全部通过后才发送验证邮件awaitsendVerificationEmail(email);});2️⃣ 频率限制Rate LimitingimportrateLimitfromexpress-rate-limit;// 限制同一 IP 的注册频率constregisterLimiterrateLimit({windowMs:60*60*1000,// 1 小时max:5,// 最多 5 次注册message:注册过于频繁请稍后再试,});// 限制同一邮箱的发送频率constemailLimiterrateLimit({windowMs:24*60*60*1000,// 24 小时max:3,// 同一邮箱最多发 3 次message:验证邮件发送过于频繁,});app.post(/register,registerLimiter,emailLimiter,async(req,res){// ...});3️⃣ 人机验证阻止自动化攻击// 使用 hCaptcha / Cloudflare Turnstile / Google reCAPTCHAimport{verifyCaptcha}from./captcha;app.post(/register,async(req,res){const{captchaToken}req.body;constisValidawaitverifyCaptcha(captchaToken);if(!isValid){returnres.status(400).json({error:人机验证失败});}// 继续注册流程...});4️⃣ 延迟发送 退信自动抑制// 使用 Resend 的 webhook 处理退信app.post(/webhooks/resend,async(req,res){const{type,data}req.body;if(typeemail.bounced){// 将该邮箱加入抑制列表suppression listawaitdb.suppressedEmails.create({email:data.to,reason:bounced,bouncedAt:newDate(),});// 标记该用户账户为可疑awaitdb.users.update({email:data.to},{status:suspicious,sendBlocked:true});}if(typeemail.complained){// 用户举报垃圾邮件立即加入黑名单awaitdb.suppressedEmails.create({email:data.to,reason:complained,});}});// 每次发送前检查抑制列表asyncfunctionsafeSendEmail(email,content){constisSuppressedawaitdb.suppressedEmails.findOne({email});if(isSuppressed){console.log(跳过已抑制邮箱:${email});return;}awaitresend.emails.send({from:...,to:email,...content});}5️⃣ 使用独立子域名发送验证邮件主域名: appyourdomain.com → 发送重要通知订单、密码重置 验证子域: verifyauth.yourdomain.com → 发送注册验证邮件这样即使验证邮件被投毒不会影响主域名的信誉重要邮件依然能正常送达。 防御层次总结攻击者提交虚假邮箱 │ ▼ ┌─────────────────────────────┐ │ 1. 人机验证 (Captcha) │ ← 阻止自动化批量注册 ├─────────────────────────────┤ │ 2. 频率限制 (Rate Limit) │ ← 限制单位时间注册量 ├─────────────────────────────┤ │ 3. 格式 临时邮箱过滤 │ ← 过滤明显无效邮箱 ├─────────────────────────────┤ │ 4. MX 记录检查 │ ← 过滤不存在域名 ├─────────────────────────────┤ │ 5. 邮箱验证 API │ ← 验证邮箱是否真实存在 ├─────────────────────────────┤ │ 6. 独立子域名发送 │ ← 隔离风险 ├─────────────────────────────┤ │ 7. 退信 Webhook 抑制列表 │ ← 自动止损 └─────────────────────────────┘ 最低成本方案适合小项目如果暂时不想接入付费验证 API至少做到✅Cloudflare Turnstile免费人机验证✅频率限制每 IP 每小时最多 3-5 次注册✅一次性邮箱黑名单disposable email domains 列表 开源免费✅Resend 退信 Webhook→ 自动加入抑制列表✅MX 记录检查免费几行代码搞定这 5 项组合起来就能挡住95% 以上的投毒攻击而且几乎零成本。