Site logo

けーろだの愚痴とえるろだの保守

情報技術も古くなるということ。

けーろだの愚痴とえるろだの保守

情報技術も古くなるということ。

はじめに

今回はけーろだ(旧ロイヤルフレア)を潰してえるろだに移行しようと思った決め手について書いていきます。

UIがカス

えるろだのウェブデザインの話で書いた通りです。使いにくいUIは苦しいですよね。

けーろだのプログラミング言語Perlでわろた

けーろだは旧ロイヤルフレアのコードを使用していました。 中身を見てみましたがPerlという言語で作られていました。 昔こそ流行っていましたが可読性が非常に低く使われなくなりました。 可読性が低いということは保守しにくいということです。何かバグや脆弱性があっても分かりにくく直しにくいです。 さらに使われないということはコミュニティも縮小し新たなライブラリも作られないということになります。基本的に使わない方が良いです。

えるろだではデータの処理を司るバックエンドに PythonfastAPI , ユーザに見せる画面を司るフロントエンドに Nuxt + Vuetify という2025年現在流行しているフレームワークを使用しています。 活発なコミュニティなので保守できる人も探せばたくさんいるはずです。僕が蒸発しても誰かが引き継げるはずでしょう。

CGI、ゴミです。

旧ロイヤルフレアは Perl という言語で CGI を使用して作成していました。 CGIはHTTPリクエストを受け取ったらそのリクエストを処理したうえで静的なHTMLファイルを作成する仕組みです。 これはすなわち 表示処理とバックエンド処理が混ざっていて非常に保守しづらいです。 下記の PerlCGI サンプルコード1を見てください。

#!/usr/bin/perl
use strict;
use warnings;
use CGI;

my $q = CGI->new;
print $q->header('text/html; charset=UTF-8');

my $user = $q->param('user') || '';

print "<html><body>\n";

if ($user eq 'admin') {
    print "<h1>Welcome, admin!</h1>\n";
    print "<p><a href=\"/admin/panel.cgi\">Go to admin panel</a></p>\n";
} elsif ($user) {
    print "<h1>Hello, $user!</h1>\n";
    print "<p><a href=\"/logout.cgi\">Logout</a></p>\n";
} else {
    print "<h1>Guest access</h1>\n";
    print "<form method=\"POST\" action=\"/login.cgi\">\n";
    print "  <input type=\"text\" name=\"user\" placeholder=\"User name\">\n";
    print "  <input type=\"submit\" value=\"Login\">\n";
    print "</form>\n";
}

print "<hr>\n";
print "<p>Powered by Perl CGI</p>\n";
print "</body></html>\n";

if文とHTMLが絡み合って実際に出力されるHTMLにどのタグが入ってくるか一瞬悩みます。 これが実際のアプリケーション規模の量になるとよりロジックが複雑になり見通しが非常に悪くなります。

特に旧ロイヤルフレアのHTMLは一部の小数作品等を除き基本1つの uploader.cgi というCGIファイルで全ての作品を賄っていました。 各々の作品で異なるリプレイフォーマットを各々の場所で解析しつつタグを作成してそれを表示…みたいな処理をすると上記コードが複雑になって見通しが悪くなることが容易に想像できるでしょう。

実際僕は旧ロイヤルフレアのコードは読めないです。ただでさえ Perl という可読性が低い言語を使用しているのに出力される HTML の想像もつかないのでロジックの全てが追いづらいです。 全てを理解している旧ロイヤルフレア開発者が存命ならまだしも、蒸発した今となっては誰も保守できないといって過言ではないです。

Perlのcrypt関数、脆弱なうえに環境依存やんけ…

東方リプレイアップローダの基本機能としてリプレイファイル投稿時に削除パスワードを設定するようになっています。 ウェブアプリの常識としてパスワードは何らかの方法で元のパスワードが分からない形で保管します。この変換はハッシュと言われます。

例えば 334 というパスワードがリプレイ投稿時にユーザから与えられたとき、サーバ側は 100 で割ったあまりを考えます。すると 34 という値が出て来ると思います。この 34 という値をサーバに保存してきます。 仮に 34 という値が侵害によって漏洩しても攻撃者は 334 という値までたどり着くことができません。よってユーザのパスワードは攻撃者にはわからないです。 ユーザは削除するとき 334 というパスワードを入力すれば、投稿時同様 100 で割り、サーバで管理されている値と同じ 34 であることが分かれば投稿時と同じパスワードを入力したユーザ本人であることの証明であると判定できます。 後は大体これを複雑にしたようなことをやっていると思ってもらって構いません。

さて、旧ロイヤルフレアでは Perlcrypt 関数を使用していました。 crypt はそもそもOS依存でハッシュアルゴリズムが変わる関数です。先の例でいうと 10 で割ったり 13 で割ったりするということですね。 これはすなわち環境を変えにくいということに繋がります。

例えばけーろだは A というクラウドサービスを使用していました。A の価格設定が変更してコストが高くなったり、そもそもけーろだが規約違反でBANされるなどして新たな移行先を考える必要が出たとします。 B を移行先にすると決めた時、 crypt 関数は同じハッシュ化をしてくれるとも限りません。これはすなわち A を使用していた時にリプレイを投稿したユーザは B に移行した後に消そうと思って同じパスワードを入力しても投稿時にサーバに保存された A によるハッシュ値と、削除時に検証する B に依存するハッシュ値が異なるため違うパスワードを入力したと認識されてしまいます。非常に厄介です。

さらに crypt 関数は昔の関数です。当然使用するハッシュが脆弱なことが考えられます。 実際にけーろだが使用していたサーバやロイヤルフレアが動いていたサーバで crypt 関数を動かしたことがないのでわかりませんが、恐らく MD5 を使用していたと考えられます。2 ググれば分かりますが MD5 は脆弱なことが知られていて非推奨なハッシュアルゴリズムであることが知られています。 具体的には総当たり攻撃でパスワードを突破しやすいということが知られています。

さて、えるろだでは MD5 よりは安全なアルゴリズムを使用しています。 dockerコンテナによってどんなサーバでも環境が統一されるので移行性もある状況ではあります。

えるろだの保守

近年の情報技術は目覚ましい進化を遂げています。 数年前は安全とされていたものもハードの進化によって危険なものになることもザラです。(MD5 もその一つです。) よって継続保守が必要不可欠です。

えるろだのソースコードは github で管理されています。 github には codeQL という無料でコードの脆弱性を検知してくれるオプションがあるので使用しています。 さらに githubdependaBot は一応使用して脆弱性があれば気づいて修正する仕組みは作成しているつもりです。(つもり)

まとめ

サービスは呪いです。一生付きまとわれる覚悟をしましょう…

Footnotes

  1. chatgptに作ってもらいました。ありがとうサムアルトマン。
  2. 旧ロイヤルフレアが作成していたアップローダ以外のその他東方スコアボード群は、作られた年もアップローダより後なのか Python で作成されています。ここでハッシュアルゴリズムに MD5 を使用していました。恐らく旧ロイヤルフレアアップローダが MD5 を使用していたためその他東方スコアボードも MD5 にしたのだろうという予想がつきます。