如何用 Upstash 为网站保驾护航
我最近发现有人故意超频刷我的接口,直接让我的 Redis 费用飞涨,本文来教你如何用 Upstash 来为你的网站添加限流与 IP 封锁等保护措施。
声明:本文并没有接受来自 Upstash 任何形式的赞助。
事件源头
前两天给博客的文章添加了一个新功能—表情回复。我觉得这样会给文章增添一点互动感,但又不想要互动感太重的评论,最后就思考了一番,决定还是给文章添加一个表情回复的功能。
毕竟现在像 Slack,iMessage,Twitter 私信,Telegram (*咳嗽*除了微信)等等类似优秀的应用都有着自己的一套“reactions”功能实现,其中 Slack 和 Telegram 的 UX 可谓是我见过实现的最好的。
然后昨天晚上我看了一眼缅怀皓哥的文章,发现有什么东西不太对劲 🤨
是的,🙏 这个表情被按了3.1万次?
根据比例来看,最多的“拥抱”表情才123次而已,那中间肯定有蹊跷。
我立马去 Upstash 后台看了一下确保是不是有人在刷我的 API 接口流量,果真如此。
从这个带宽图表可以看出,从0点左右开始我的 Upstash Redis 读写数开始飙涨,最高期甚至还达到了每秒1000次请求,我看到的时候心想:“这谁啊跟我血海深仇,也太离谱了吧?”。
因为整个表情回复的功能我实现的也挺匆忙,基本上当天下午就写完了,而且也是给个人网站做的功能,就没考虑过多,否则的话我可能会加上单元测试,e2e 测试以及各种安全验证手段确保只有我自己才能访问等等。
万万没想到,我刚刚实现这功能的当天就有喜欢作恶的人来“搞”我。
那你可能会问:“这个会影响什么呢?”
因为我的整个博客网站架构是全 Serverless + Edge 部署的,所以像 Redis 这种 KV 存储我必须得用支持 Serverless 架构的才行,那么调查了一番以后就发现,Upstash 是现在最靠谱的服务商。
但是 Upstash 的收费规则是按量的,很合理,也就是每10万次读写需要花$0.4。
那么也就意味着我的 Redis 读写量越高,我要缴的钱就越多。
想到这里,我立马进入了防守模式。
Rate limit 限流
其实解决方案在本文分了两个阶段,第一阶段就是在我发现了以后,花了10分钟加了 Upstash 提供的官方 rate limit 来进行对我的接口限流保护。
可以在我的 GitHub commit 里看到完整的代码。
我再次查看了 Upstash 后台仪表盘,成功限流!
然后我就安心地去睡了。
谁曾想,此人并没有罢休。
我第二天早上起来发现 Upstash 仍然有着很稳定的一条用量线条:
我无语了,也就是说我限流了以后这人仍然在限流内最大值频繁地刷着请求数。。。
我内心一句“好家伙”,逼我直接封你 IP 呗,我看你还怎么继续?
IP 封锁
实在是忍无可忍,我在 Upstash 面板找到了请求被限流最多的人的 IP 地址(因为我在 rate limit 的限流里回传了对方的 IP 作为 key 的一部分方便我做分析处理)
为了能够让 IP 封锁快速生效,并且在不需要重新部署构建的前提下,我想到了完全可以利用 Vercel 的 Edge Config。
用 Edge Config 就可以帮助我存储动态方便改变的配置,而我原来就配置了官网短链的重定向,比如访问 cali.so/twitter 就可以前往我的官方 Twitter 链接。
我三下五除二就把这个人的 IP 地址给添加到了我的 Edge Config 里:
然后在自己的 Next.js 项目里可以很轻松的在任意支持 Edge 的运行时的地方去从 Edge Config 中获取值,比如说利用 Edge Middleware 可以确保在所有请求执行之前去检测:
代码量可谓是非常少了,这也正是为什么 Upstash DX 体验这么好的原因之一,集成起来不啰嗦,恰到好处。
查看完整代码变更:GitHub commit。
所以现在只要 IP 出现在 Vercel 后台定义好了的 IP 黑名单内,就会默认被拒绝一切页面和接口的访问。
舒服了。
我赶紧提交了代码,Vercel 花了2分钟部署完毕。
过了一会儿,果真效果显著!
我们一起来看看完整的流量图:
图上的三处时段解释:
- 1是开始刷我流量的时候。
- 2是我开启了 rate limit 限流功能后。
- 3是我加了 IP 封锁功能后。
哎,看来这个人目前是平息下来了,我也不了解他的出发点是什么,纯属为了让我更花钱吗?
他要是再来一次换一个新的 IP,那我要操作的成本其实就很小了,添加多一个 IP 而已。而对于他每次新开一个 DigitalOcean VPS 实例反而是一件成本更大的事情,如果他真的卷土重来,我也奉陪到底。
说到这那有人可能会问,这种要想黑名单别人的 IP 或者限流不是很简单吗?比如用 NGINX 都可以做到,为什么要用其他的第三方服务?
为什么选择 Serverless
因为我选择的是无服务器架构,其实并不是顾名思义的意思,因为我们并没有用另外一种实体去代替服务器本身,只不过做了一层抽离,就是说并没有一个服务器单例在某个数据中心24小时无间断地为你运行着而已。
这种做法可以让开发者专注于代码,而不用去管理自己的 VPS 或者单例服务器,那也就代表着可以多花时间写业务代码而不是忙碌建立稳定可拓展的基础架构(比如担心实例是否宕机了,焦虑自己的 NGINX 有没有在正常运转,不清楚数据库进程有没有报错等等)
就像无糖可乐并不是真的无“糖”一样,这里的无糖指的是无蔗糖,但是为了提供甜味,还是会添加代糖的。
我个人是非常喜欢这种 Serverless 计算架构的,也导致我几乎每个 web 项目都利用了 Vercel 来部署 Serverless 网站和应用。
因为 DX(开发者体验)对我来说,真的很重要。
总结
互联网上作恶多端的人其实也不少,我们还是要尽可能的确保能被公开访问的资源有所方法做到限流和封 IP 行为,不一定要像 OpenAI 一样风控那么严厉,但起码还是要留一手的。
我猜测最近 Next.js 13.4 宣布的 Server Actions 也许可以一定程度释放自己写 API 接口给自己第一方网站/应用调用的需求,因为就完全不公开任何 API 接口了,自然就少了这个他人恶意刷你接口的潜在可能性。
这种猫和老鼠的游戏,其实也没有一劳永逸的办法,最后还是得在自己的服务端做好安全防护。
但无论如何,我们还是要尽可能在自己的网站里做好相对应的防护措施,以及经常关注自己使用的第三方服务用量,避免被这些人钻了空子。