LoginSignup
45
34

More than 1 year has passed since last update.

Next.js の Middleware を使ってサクッと迷惑 Bot たちを追い払う

Posted at

こんにちは。ぬこすけです。

皆さんは Bot のアクセスに悩まされたことはありますか?

私はあります。

私が個人開発しているサイトでも Bot からガンガンアクセスがきます。
スクリーンショット 2022-08-18 22.25.04.png

1ページリクエストすると画像や js ファイルなどの追加のリクエストも走るのでやっかいです。
私のサイトは Cloud Run で動かしていますが、リクエストに比例して料金が加算するようにしているので、 Bot からの余計なリクエストを抑えてお財布に優しくしたいところです。

一方で、 Next.js のバージョン 12.2 で Middleware という機能が安定版としてリリースされました。

この Middleware という機能を使えば、 ユーザーからのリクエストが来た時にページを返却する前にコードを実行することができます
例えば、ユーザーエージェントを判定してリダイレクトをしたり、Basic認証をかけたり、みたいなことができます。

今回は Middleware を使ってこの迷惑 Bot たちを追い払います

やることは簡単です。

  1. public ディレクトリ配下に Bot 用の html ファイルを用意しておく。
  2. プロジェクトのルート配下に middleware.js(ts) を置いて 20 行くらいコード書く。

はい、終わりです。
するとこんな感じでステータスコード 403(Forbidden) で返却することができます。

nukopro_bot_access_log.png

詳しく説明していきます。

1. public ディレクトリ配下に Bot 用の html ファイルを用意しておく。

Bot 向けに表示する html ファイルを用意します。
例えば次のような 403.html を用意して public 配下に置きます。

403.html
<html lang='ja'>
  <head>
    <title>Forbidden</title>
    <meta name='robots' content='noindex' />
  </head>
  <body>
    <p>
      Forbidden
    </p>
  </body>
</html>

Bot 相手なので凝った html を用意しなくて大丈夫でしょう。

2. プロジェクトのルート配下に middleware.js(ts) を置いて 20 行くらいコード書く。

Next.js ではプロジェクトのルートディレクト直下に middleware.js ( TypeScript なら middleware.ts )を置くことで Middleware 機能を使うことができます。
次のような middleware.js を用意しましょう。

middleware.js
import { NextResponse, userAgent } from 'next/server';

// 追い払いたい Bot たち
const uaBlackList = Object.freeze([
  'PetalBot',
  'SemrushBot',
]);

export function middleware(req) {
  const { ua } = userAgent(req);
  // robot.txt へのアクセスは除く
  if (
    uaBlackList.some((blackUa) => ua.indexOf(blackUa) > -1) &&
    req.nextUrl.pathname !== '/robots.txt'
  ) {
    req.nextUrl.pathname = '/403.html';
    return NextResponse.rewrite(req.nextUrl, { status: 403 });
  }
  return NextResponse.next();
}

この middleware.js では予め定義したブラックリストに含まれる Bot からアクセスが来た時は 403.html を表示し、それ以外の場合は通常通りページを表示します。

あとは本番環境にデプロイして終わりです。
ユーザーエージェントを Bot に偽装してページにアクセスすると次のような画面が表示されます。

スクリーンショット 2022-08-18 22.16.12.png

[余談] html じゃなくて Next.js のカスタムエラーページを表示しないの?

余談なので読み飛ばしても大丈夫です。

Next.js には pages/404.jsx のようにカスタムエラーページを表示する機能がありますが、これは使いません

というのも、カスタムエラーページを表示した場合、さらに余計なリクエストが middleware に来てしまうことがあるから です。

例えば全ページ共通の _document.jsx に次のような jsx が定義されていたとします。

_document.jsx
export default function Document() {
  return (
    <Html lang='ja'>
      <Head>
        ...
        <link rel='icon' href='/images/icons/icon-16x16.png' sizes='16x16' type='image/png' />
        ...
      </Head>
      ...
    </Html>
  );
}

この場合、 Bot からアクセスが来て pages/404.jsx を表示しても、さらに /images/icons/icon-16x16.png へ追加のリクエストが飛んできます。
できれば、余計な Bot からはリクエストを抑えたいので 403.html のような静的なファイルを用意しています。

まとめ

  1. public ディレクトリ配下に Bot 用の html ファイルを用意しておく。
  2. プロジェクトのルート配下に middleware.js(ts) を置いて 20 行くらいコード書く。

これだけでサクッと Bot からの余計なアクセスを抑えることができました。

Next.js で Bot のアクセス対策をしたい時はぜひ参考にしてみてください!

45
34
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
45
34