0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Nginx / Next.js】実装していない /api/action にPOSTされ cron を仕込まれた話

0
Posted at

はじめに

ある日、サーバーを確認すると 意図しない cron が設置されていました。
調査を進めると、自分では一度も実装した覚えのない /api/action に対する POST リクエストが、侵入時刻直前に大量に飛んでいることが判明しました。

環境

Nginx(Reverse Proxy)
Next.js(Node.js、localhost:3000)

構成

Internet

Nginx :443
↓ proxy_pass
Next.js (localhost:3000)

事象

cron の作成時刻(2026/01/15 17:15 頃)前後の Nginx access.log を確認すると、以下のようなログが集中していました。

79.110.49.221 - - [15/Jan/2026:17:15:40 +0900] "POST /api/action HTTP/1.1" 500 207 "-" "Mozilla/5.0" "-"
79.110.49.221 - - [15/Jan/2026:17:15:42 +0900] "POST /_next/data HTTP/1.1" 444 0 "-" "Mozilla/5.0" "-"
79.110.49.221 - - [15/Jan/2026:17:15:54 +0900] "POST / HTTP/1.1" 444 0 "-" "Mozilla/5.0" "-"

ポイントは以下です。

  • / や /_next/data → 444(Nginxで遮断)
  • /api/action → 500(アプリ側でエラー)

違和感①

/api/action に POST すると 404 になる

curl -X POST https://example.com/api/action
# → 404

しかしログ上では 明確に 500。

→「実装した覚えのない API が、なぜ 500 を返すのか?」

error.log から分かった決定的事実

同時刻の error.log を確認すると、以下のログがありました。

a client request body is buffered to a temporary file
/var/lib/nginx/tmp/client_body/0000000177,
request: "POST /api/action HTTP/1.1"

これは何を意味するか?

  • POST ボディが Nginx のメモリに収まらないほど大きい
  • /api/action 宛ての 実体のあるリクエストボディ が存在
  • Nginx は アプリにリクエストを転送している

「/api/action が存在した」証拠ではなく、
「/api/action が proxy_pass でアプリに届いていた」証拠

Nginx 設定の確認

location / {
    proxy_pass http://localhost:3000;
}

この設定により、

  • /api/action というパスが 存在しなくても
  • そのまま Next.js 側に転送される
    という構成でした。

なぜ「404ではなく500」だったのか

結論として、以下の可能性が高い。

  • /api/* をまとめて処理する共通処理(body parser 等)が存在
  • 攻撃者が 巨大な POST ペイロード を送信
  • ルーティングに到達する前に アプリが例外で落ちる
  • 結果として 500 が返る

つまり、
/api/action が「実装されていた」のではなく
「存在しないパスでも処理途中でクラッシュした」

cron が仕込まれた理由(推測)

ログだけでは断定できませんが、状況証拠から以下が考えられる。

  • 大容量 POST による処理系の不具合
  • 一時的に RCE 相当の状態 が成立
  • cron を設置される

再発防止のために行った対策

  1. POST サイズ制限
client_max_body_size 2m;
  1. /api/action を明示的に遮断
location = /api/action {
    return 444;
}

学び

  • 「実装していない API = 安全」ではない
  • proxy_pass 配下では
    存在しないパスでもアプリに届く
  • 500 は「サーバが悪い」のではなく
    「アプリが何かを処理しようとした」証拠
  • Nginx の error.log は
    攻撃内容を語ることがある

おわりに

今回の件は、

  • アクセスログ
  • error.log
  • 設定ファイル
    を時系列で突き合わせることで、かなり確度の高い推測ができました。

同じように
「見覚えのない API が叩かれている」
「404 のはずなのに 500 が出ている」
という状況に遭遇した人の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?