dwgx@blog:~$dwgx
> cd ../posts

strict: 自分の MC サーバーはログインハンドシェイクでモッドを検証する

// created

strict は Fabric サーバー側で動くログイン準入モッドで、やることは一つ。プレイヤーがログインする瞬間にモッドとトークンを検証し、合わなければ即キックする。バニラのオンライン認証はあなたが正規アカウントかどうかしか見ず、何をインストールしているかは見ないので、X-ray の鉱石透視や飛行、自動釣りといったクライアントモッドはバニラサーバーにそのまま入れてしまう。strict はその関門をログインハンドシェイクに移す。1.21.3、Java 21 で動き、Fabric Loom でビルド、リポジトリは github.com/dwgx/strict

コアはログインハンドシェイクに割り込むこと。ServerLoginConnectionEvents.QUERY_START に hook し、サーバーはカスタムチャンネル strict:check を通じてクライアントにデータを要求する。クライアントの ClientNetworkingCheckPayload を返し、その中に二つを詰め込む。一つは AES-GCM で暗号化したトークン、もう一つは現在ロード済みの完全なモッドリスト。サーバーはまず復号して SHA-256 を検証し、次に nonce が十分以内に重複していないか、タイムスタンプが五分以内に新鮮かを確認し、最後にようやくモッドポリシーと照合する。

なぜモッドリストだけ検証しないのか。リストはクライアントが自己申告するもので、申告できるということは偽装もできる。トークンの層はこの返信が確かに自分のモッドが今しがた送ったものだと証明し、nonce はリプレイを防ぎ、タイムスタンプはパケットをキャプチャしてじっくり使うのを防ぐ。暗号化・復号とハッシュはすべて CryptoUtils にあり、鍵は secretKey から派生する。ここに落とし穴を埋めてある。デフォルト値 dwgx1337 は手抜きテスト用に残したもので、そのままサーバーを立てて変更しないのは防御ゼロと同じ。ドキュメントでもわざわざ声を大にして注意している。

アクセス制御は二つのモード。公開モードは検証を通れば入れて、OP は素通り。私密モードのほうが面白い。よそ者は pendingPlayers に引っかかり、まず切断されて承認を待たされ、管理者のチャット欄にはクリックできる [Accept] / [Reject] / [Blacklist] が出る。ワンクリックで済み、コマンドを覚える必要はない。ブラックリストは UUID もマシン名も対応し、報告には OS ユーザー名も付くので、サブ垢に切り替えるいたずらっ子に対して多少は効く。

設定は config/strict/config.yml にある。allowedMods / excludedMods でホワイト・ブラックリストを管理し、allowFabricMods を有効にすると fabric- 接頭辞の公式モッドを自動で通す。コマンドはすべて /strict の下、OP4 レベルで、モード切り替え、承認、/strict reload による再起動不要のホットリロードができる。今のところ 1.0-SNAPSHOT は 1.21.3 に固定で縛られており、自分でサーバーを立てるついでに作った実験だ。