ゲームアツマールはもちろん、web公開のツクールゲームは基本的にセキュリティがガバガバです。
知識のある人なら、やろうと思えばセーブデータはいくらでも改変できますし、本来ゲームには組み込まれていない動作をさせる事だってできちゃいます。
当サイトのゲームはプログラムを難読化しているので、よほど暇な技術者でない限りハッキングなんてしないと思うのですが、セーブデータの改変くらいなら、少し試行錯誤すればできてしまう状況だったのですよね。
一人用のゲームならともかく、多人数参加型のゲームにおいては、一人の不正行為によって他の多くのユーザーが嫌な思いをします。その結果、ゲームへの不満が募ったり、ゲームに見切りを付けたユーザーが離脱してしまう事があります(筆者の実話です)
そこで、簡単にではありますが、セーブデータの改変対策に取り組んでみる事にしました。自分でスクリプトを書けるクリエイターに向けた内容になりますが、少しでも参考になれば幸いです。
どうすればセーブデータを改変できるのか?
特別なツールを使う必要はなく、Web公開中のゲームはブラウザを使って中身を簡単に操作できてしまうのです。
『RPGツクールMZ』などでゲームをテストプレイ中に「F12」キーを押すと「デベロッパーツール」が起動して、ゲームのログを確認したり、任意のコードを実行したりできるのはご存じかと思います。これはブラウザでも同じなのです。
ゲームアツマールなら「F12」でデベロッパーツールを開き、コンソールの上部「top」と書かれた部分をクリックして、「gamePlayer(index.html)」を選択すればOK。ツクールでのデバッグと同様にゲームの中身をいじる事ができます。
例えばこのコンソールに「$gameParty」と入力してエンターを押してみましょう。すると「Game_Party」オブジェクトが表示されてますので、クリックして展開します。
ここに、「_gold」という項目がありますね。これはツクールにおける所持金を記録している変数です。ダブルクリックすると、数字を書き換える事ができます。
例えば、「0」を「10000」に書き換えるだけで……所持金が「10000G」になりました!
このように、ツクールのセーブデータは特別なツールを使わなくても簡単に書き換えてしまう事ができるのです。
これはクリエイターにとっては、テストプレイの際にも、公開後にエラーの原因を突き止めるためにも大変便利な機能です。その反面、悪意あるユーザーによる不正行為の温床にもなります。
しかも、なんとデベロッパーツールによる書き換えを防ぐ手段はありません!
残念ながら、完全に不正を防ぐ事は出来ないのです……。しかし、上記のような簡単な方法でセーブデータを書き換え可能という状態はあまりにセキュリティが甘すぎます。せめてこの状況だけは打開したいところです。
セーブデータの書き換えを監視する
上記の対策として、セーブデータが意図せぬ場面で書き換えられていないか監視するため、以下のようなプラグインを書きました。所持金を監視するプラグインの一例です。
function ProtectSavedata() { throw new Error('This is a static class'); }
// 所持金を監視するための変数
ProtectSavedata.gold;
// シーン更新処理を上書き
const _Scene_Base_update = Scene_Base.prototype.update;
Scene_Base.prototype.update = function () {
_Scene_Base_update.apply(this, arguments);
// 監視用の変数が空の場合は所持金の値を代入
if (ProtectSavedata.gold === undefined) ProtectSavedata.gold = $gameParty.gold();
// 所持金が監視用変数の値と異なる場合、ゲームを停止する
if ($gameParty.gold() !== ProtectSavedata.gold) SceneManager.stop();
};
// 所持金を増やす処理を上書き
const _Game_Party_gainGold = Game_Party.prototype.gainGold;
Game_Party.prototype.gainGold = function (amount) {
_Game_Party_gainGold.apply(this, arguments);
// 監視用の変数に新たな所持金の値を反映させる
ProtectSavedata.gold = $gameParty.gold();
};
// 所持金を減らす処理を上書き
const _Game_Party_loseGold = Game_Party.prototype.loseGold;
Game_Party.prototype.loseGold = function (amount) {
_Game_Party_loseGold.apply(this, arguments);
// 監視用の変数に新たな所持金の値を反映させる
ProtectSavedata.gold = $gameParty.gold();
};
上記のプラグインは内容を読んでいただければ分かるかと思いますが、「所持金を増減させるメソッドを通さずに直接書き換えようとした場合はゲームを停止する」という動作になっています。
これで、ブラウザのデベロッパーツールから変数の中身を直接書き換える事はできません。
所持金以外の変数についても同様のスクリプトを書けば監視対象に加える事ができますが、あまりに多くの変数を監視すると動作が重くなるのでほどほどに
しかし、このままだとデベロッパーツールから「所持金を増減させるメソッド」を呼び出せば所持金の値は改変できてしまいますよね?
そうです。それも考慮に入れるなら、新たに「所持金を増やすメソッドであると分からない独自のメソッド」を作ってしまいましょう!
さらにプログラム全体を圧縮して難読化したり、所持金が変更された場合はログを残して不正をチェックできる仕組みを作っても良いです。凝れば凝るほど、セーブデータの改変は難しくなるでしょう。
まとめ
一般的なゲームユーザーはデベロッパーツールの使い方なんて知らないでしょうし、もし変数の書き換え方を知っていたとしても、ゲームのプログラムまで解析する事は無いはずです。
また、ある程度知識のある人だって難読化したプログラムを解析するほど暇ではないでしょう。デフォのツクールゲームならともかく、凝った対策をしているゲームを解析するとなると、もはや執念の作業です。そこまでして不正行為を行う人がいるとすれば、そのゲームがよほど魅力的なのでしょう。
結論としましては、通常のツクールゲームの場合、Webで公開する以上、完ペキな不正対策はできないと割り切るのが一番です。javascriptで動作している限り不正を完全に防ぐ事はできません。
多人数参加型のゲームなど、他のユーザーに迷惑がかかる可能性があるゲームを公開する場合は、トラブル防止のためにも、セーブデータの改変対策に取り組んでみることをオススメします。