> 所有日志都是从 `Nginx` 的 `access.log` 中提取的。其中的 `IP` 信息为攻击者的`代理 IP`,且取出了 `Cloudflare` 的 `IP`。
# 收到新评论通知邮件
当我打开邮箱后提示有 5 封邮件未读,邮件的时间是间歇性的。一开始以为只是良性测试,但没过多久就冒出了大量重复的评论。

邮件的内容大致如下:
```text
您的博客有新的评论!
johnniang, 您好!
有访客在《ARTS-w002》留言:
YYY:YYY
你可以点击查看完整内容
```
发送频率如下:
|序号|时间|
|-------|-------|
|1|Dec 6, 2019 7:08 PM|
|2|Dec 6, 2019 7:09 PM|
|3|Dec 6, 2019 7:16 PM|
|4|Dec 6, 2019 7:17 PM|
|5|Dec 6, 2019 7:18 PM|
---
# 对方产生邪恶的念头
该访客试探性地评论我的博客,发现并不需要审核就能够评论,接着就产生了邪恶的念头......
由于[`评论接口`](https://github.com/halo-dev/halo/blob/0e1163ea66339fc12cb6b842ae88fcb165c624a9/src/main/java/run/halo/app/controller/content/api/PostController.java#L134)是限制了连续快速请求的,该攻击者一开始并不知道评论的具体间隔时间,然后不断地试探 `rate limit`(如果仔细阅读过[`源码`](https://github.com/halo-dev/halo/blob/0e1163ea66339fc12cb6b842ae88fcb165c624a9/src/main/java/run/halo/app/controller/content/api/PostController.java#L134)就会发现,默认的 `rate limit` 时间其实是 `5s`)。
---
# 对方实施攻击计划
该攻击者迅速编写了 `Python` 脚本,准备攻击评论接口。
```nginx
[06/Dec/2019:11:39:29 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:29 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:30 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:49 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 337 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:50 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:50 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:51 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
[06/Dec/2019:11:39:51 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "python-requests/2.22.0" "161.117.xxx.xxx"
```
从日志中看到,出现了 400 的错误(`Frequnt Access`),该访客可能还未猜出精确的间隔时间。但攻击者仍不放弃,继续试图从浏览器上寻找评论的 `rate limit`:
```nginx
[06/Dec/2019:11:40:18 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "https://johnniang.me/archives/arts-2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:40:26 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "https://johnniang.me/archives/arts-2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:40:31 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "https://johnniang.me/archives/arts-2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
可能是在浏览器上`点起来`不爽,于是又给 `Python` 穿上马甲(伪装 User-Agent)继续试探:
```nginx
[06/Dec/2019:11:41:58 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:41:58 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:41:59 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:42:11 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:42:12 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:42:59 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:43:09 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 428 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:43:10 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 279 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
从攻击的规律来看,一直在评论我的[`一篇文章`](https://johnniang.me/archives/arts-2),为了不给我其他访客造成影响,我只能被迫开启文章的评论审核功能。
最终,该攻击者终于找到了评论接口的 `rate limit`,于是间隔 `5s` 就发送一个 `POST` 请求:
```nginx
[06/Dec/2019:11:47:54 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:00 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:05 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:11 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:16 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:22 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:27 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:48:33 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
---
# 尝试禁用该篇文章的评论
此后邮箱的状况如下图:

几乎所有的恶意评论都指向的同一篇文章,我尝试禁用该篇文章的评论功能(减少正常访客的影响)。
---
# 对方继续被追击
好景不长,攻击者随即发现了请求中出现了大量的 `400` 错误,于是就通过电脑的浏览器访问我的博客的被攻击的文章,评论之后才发现该篇文章的评论功能已经被禁用:
```nginx
[06/Dec/2019:11:55:27 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:30 +0000] "GET /archives/arts-2 HTTP/1.1" 200 19072 "https://johnniang.me/archives" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:32 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
攻击者继续访问我的其他文章,发现其他文章的评论功能是正常的。
```nginx
[06/Dec/2019:11:55:35 +0000] "GET /archives HTTP/1.1" 200 13396 "https://johnniang.me/archives/arts-2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:36 +0000] "GET /archives/a1074-reversing-linked-list HTTP/1.1" 200 15191 "https://johnniang.me/archives" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:37 +0000] "GET /api/content/options/comment HTTP/1.1" 200 106 "https://johnniang.me/archives/a1074-reversing-linked-list" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:37 +0000] "GET /api/content/posts/37/comments/top_view?page=0&sort=&size=5&total=0 HTTP/1.1" 200 1034 "https://johnniang.me/archives/a1074-reversing-linked-list" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:55:38 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:16 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:22 +0000] "POST /api/content/posts/comments HTTP/1.1" 404 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:27 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:33 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:39 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:44 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:11:57:50 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
于是攻击者的`武器`升级了,开始`乱抢扫射`,遍历文章的 `ID` (该 `ID` 是从 1 开始的自增属性)并发送评论请求。我的邮箱就这么被`狂轰滥炸`(轻微):

---
# 被迫关闭评论的 `API`
最后只能被迫关闭评论接口这个 `API` 了。同时也导致正常访客无法正常发送评论(攻击者的目的也达到了)。
---
# 对方终于放弃
在得到大量的 `403` 错误之后,对方终于放弃了。
```nginx
[06/Dec/2019:12:00:18 +0000] "POST /api/content/posts/comments HTTP/1.1" 404 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:12:00:24 +0000] "POST /api/content/posts/comments HTTP/1.1" 400 95 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:12:00:31 +0000] "POST /api/content/posts/comments HTTP/1.1" 200 427 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:12:00:37 +0000] "POST /api/content/posts/comments HTTP/1.1" 403 99 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
[06/Dec/2019:12:00:42 +0000] "POST /api/content/posts/comments HTTP/1.1" 403 99 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3835.0 Safari/537.36" "161.117.xxx.xxx"
```
---
# 不足
接口的限制不够灵活,仍然能够被有效地攻击。需要一个有效的限制策略,比如限制频率为 5s、1min、30min、1hour、3hour、6hour、12hours、24hours 等等。

被“恶意评论”骚扰的全过程