1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mastodonの許可制登録に来る bp+hex スパムを cron で自動却下する

1
Last updated at Posted at 2026-09-12

私のmastodonは許可制にしているのに、承認待ちが機械的なSPAM登録で大量に埋まり承認/却下の手間が取られ、ここのところ問題になっていました。
今日は1日で100件以上のSPAM登録申請が押し寄せており、これはもう限界だと言うことで、自動却下の仕組みをもり混みました。

スクリーンショット 2026-09-12 22.53.54.png

この記事では、ユーザー名が bp + 16桁hex の申請だけを、管理画面の「却下」と同じ経路で定期削除した手順をまとめます。

対象は Mastodon 4.7.x / Docker Compose です。承認済みアカウントは触りません。

来ていた申請の形

承認待ちに、次の型が短時間で大量に並びました。多い日は100件を超えます。

項目 中身
ユーザー名 bp + 16桁の hex(例: bp6930842f68cfc730)
参加理由 Automatedprotocoldeliverabilityprobeone の使い回し
投稿 / フォロワー どちらも 0
メール docomo.ne.jp / yahoo.co.jp / gmail.com などがバラバラ
IP 日本のコンシューマ回線が毎回違う

ユーザー名は機械生成の指紋がはっきりしています。一方でメールとIPは正当な日本ユーザーと重なるので、ドメインブロックやIPルールは使えません。

同じ時期に、ユーザー名に規則がなく参加理由だけそれらしい申請も来ます。こちらは正規表現では切れないので、この記事の対象外です。

公式機能だけで足りない理由

Mastodon 4.5 以降の Username blocks は、単語の完全一致か部分一致です。^bp[0-9a-f]{16}$ のような正規表現は書けません。bp の部分一致にすると blueprint なども弾きます。

そのほか、次の手段もこの波には向きません。

  • IPルール: 発信元が毎回違う
  • メールドメインブロック: キャリアメールや大手フリーメールを巻き込む
  • tootctl accounts approve: 一括承認はあるが、一括却下はない
  • 許可制そのもの: ログインは正まるが、承認待ちと確認メールは残る

hCaptcha はメール確認時に出ます。未確認のままキューに溜まる分は止まりません。

方針

自動で切る条件を狭くします。

  1. User.pending(未承認)だけを見る
  2. ユーザー名が \Abp[0-9a-f]{16}\z のときだけ却下する
  3. 却下は管理画面と同じく、停止してから AccountDeletionWorker に渡す
  4. 既存の申請は人手で消し、今後分だけ定期実行する

承認済みの正規ユーザーは、ユーザー名が偶然似ていても対象になりません。

却下する Ruby

コンテナ内で rails runner します。

# frozen_string_literal: true

PATTERN = /\Abp[0-9a-f]{16}\z/i
rejected = 0

Account.joins(:user).merge(User.pending).find_each do |account|
  next unless account.username.match?(PATTERN)

  account.suspend!(origin: :local)
  AccountDeletionWorker.perform_async(account.id, 'reserve_username' => false, 'reserve_email' => false)
  rejected += 1
  puts "rejected #{account.username}"
end

puts "rejected_count=#{rejected}"

AccountDeletionWorker は、停止済み(unavailable?)でないと削除しません。先に suspend! してから enqueue します。ユーザー名とメールは予約せず、再利用できる状態に戻します。

先に件数だけ見るときは、suspend! の代わりに puts する dry-run にすれば足ります。

cron 用のラッパー

rails runner は起動に十数秒かかります。二重起動を避けるため flock を付けます。

#!/bin/bash
set -euo pipefail

LOCK=/tmp/reject-bp-hex-spam.lock
SCRIPT_DIR=/home/ubuntu/mastodon/scripts
COMPOSE_DIR=/home/ubuntu/mastodon/mastodon

exec 9>"$LOCK"
if ! flock -n 9; then
  echo "$(date -Iseconds) skip: already running"
  exit 0
fi

cd "$COMPOSE_DIR"
echo "$(date -Iseconds) start"
docker compose exec -T web bundle exec rails runner "$(cat "$SCRIPT_DIR/reject_bp_hex_spam.rb")"
echo "$(date -Iseconds) done"

ホスト側の Ruby ファイルを、引数としてコンテナの rails runner に渡しています。公式イメージの中身は書き換えません。

仕込み

初回は手動で一度走らせて、rejected_count とログを確認します。問題なければ5分ごとにします。

chmod 755 /home/ubuntu/mastodon/scripts/reject-bp-hex-spam.sh

crontab -l 2>/dev/null | grep -v reject-bp-hex-spam.sh; \
  echo '*/5 * * * * /home/ubuntu/mastodon/scripts/reject-bp-hex-spam.sh >> /home/ubuntu/mastodon/logs/reject-bp-hex-spam.log 2>&1' \
  | crontab -

ログは /home/ubuntu/mastodon/logs/reject-bp-hex-spam.log です。空振りのときは rejected_count=0 だけが残ります。

止めるとき:

crontab -l | grep -v reject-bp-hex-spam.sh | crontab -

運用上の境界

  • ユーザー名のプレフィックスが変わったら、正規表現を直す
  • 理由文の使い回しや、規則のない申請は見ない
  • 承認待を「すべて却下」するボタンは使わない。正当な申請が混ざる

許可制のままキューだけ自動で空ける、という割り切りです。登録そのものを止めたい波が続くなら、一時的な登録クローズや招待制の方が確実です。

運用チェック

cron は問題なく動いています。 5分ごとに欠けなく起動し、失敗はありません。

スクリーンショット 2026-09-12 23.33.31.png

参考

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?