マガジン

セーブデータの改ざんは防げるか:現実的な対策

遊びをつくる

執筆にClaudeを使用しています。

スマートフォンとノートパソコンの枠を、赤いゲームの駒と雲のアーチがつなぐ切り絵
記事のテーマをもとに制作したAI生成イラスト。

ブラウザゲームのセーブデータは、プレイヤーの手元に保存されることが多いです。localStorageやクッキーに書き込んだデータは、ブラウザの開発者ツールを開けば数秒で書き換えられます。「スコアを99999にする」「所持金を増やす」といった改ざんは、技術的な知識がそれほどなくても実行できます。 では、作者はどこまで防げるのでしょうか。結論から言えば、「クライアント側だけで完全には防げない」が正直な答えです。しかし「完全には防げない」と「何もできない」はまったく別の話です。ゲームの性質と想定リスクに応じた対策を選ぶことで、カジュアルな改ざんの大半を防ぎ、悪意のある操作のコストを十分に高くできます。この記事では、その判断基準と具体的な実装の考え方を整理します。

この記事の目次
  1. なぜクライアント側のデータは改ざんされやすいのか
  2. 対策を選ぶ前に:リスクの大きさを整理する
  3. クライアント側でできる現実的な対策
  4. サーバー側の検証が必要になるケース
  5. 実装の優先順位と判断の目安
  6. 次の行動
  7. 参考資料

なぜクライアント側のデータは改ざんされやすいのか

ブラウザゲームにおいて、localStorage.setItem('score', 100) のように保存されたデータは、そのままの形でブラウザに蓄積されます。開発者ツールの「Application」タブを開けば、キーと値が一覧できます。JSONをそのまま保存している場合、構造もすぐにわかります。

根本的な問題は、「ゲームのロジックとデータが同じ環境に存在する」ことです。サーバーサイドのゲームであれば、スコア計算はサーバーで行われ、プレイヤーは結果を受け取るだけです。ブラウザゲームはその逆で、すべての計算がプレイヤーの手元で行われ、結果もその場に保存されます。開発者ツールで見えるものは、原則として書き換えられると考えてよいです。

この前提を受け入れたうえで、「どこまで防ぐ必要があるか」を決めることが対策の出発点になります。

対策を選ぶ前に:リスクの大きさを整理する

すべてのゲームに同じ対策が必要なわけではありません。次の問いで自分のゲームのリスク水準を確認してください。

  • ランキングやスコアを他のプレイヤーと共有するか:共有する場合、改ざんは他のプレイヤーの体験を直接損ないます。対策の優先度が高いです。
  • ゲームの進行や達成感がセーブデータに強く依存するか:「強くてニューゲーム」などのやりこみ要素がある場合、改ざんでゲームバランスが崩れる影響は主に本人に留まります。
  • セーブデータが課金や報酬と連動するか:連動する場合は、クライアント側の対策だけでは不十分で、サーバー検証が必要です。
  • 一人プレイのみで、スコアを外部に送信しないか:この場合、改ざんによる被害は本人の体験に限られます。対策コストを低く抑えてよいです。

クライアント側でできる現実的な対策

チェックサムを付加する

最も手軽な対策は、保存するデータにチェックサム(整合性を確認するための値)を添付することです。具体的には、スコアや進行データをJSON文字列に変換し、その文字列から独自のハッシュ値を計算して一緒に保存します。読み込み時に再計算し、値が一致しなければ「データが破損または改ざんされた」として初期化する、というフローです。

保存:{ score: 1500, hash: "計算した値" }
読込:scoreからhashを再計算 → 保存されたhashと比較

この方法の限界は、ゲームのJavaScriptコードを読めばハッシュの計算方法がわかってしまうことです。ただし、「開発者ツールで値を直接書き換えるだけ」という最も手軽な改ざんは防げます。ハッシュを破って改ざんするにはコードの読解が必要になるため、カジュアルな操作には十分なハードルになります。

データを難読化・暗号化する

チェックサムより一歩進んだ対策として、保存前にデータを変換する方法があります。単純な例では、スコアをそのまま保存するのではなく、固定の値を足したりXOR演算を加えたりして「そのままでは読めない形」で保存します。

ただし、これも「コードを読めば解読できる」という限界は同じです。JavaScriptはブラウザ上でそのまま実行されるため、ミニファイ(圧縮・難読化)しても、解析ツールを使えば読み解かれます。暗号化の鍵もコード内に埋め込む以上、完全な秘密にはなりません。

それでも「一目で意味がわからないデータ形式にする」だけで、大半の改ざん試みを防げます。コストと効果のバランスとしては現実的な選択肢です。

セーブデータの構造を間接的にする

スコアを直接保存するのではなく、「プレイの履歴」を保存してスコアはそこから再計算する、という設計も有効です。たとえば「面1クリア・面2クリア・コイン取得×3」という記録からスコアを導く形にすると、スコアの数値だけを書き換えても、次回起動時に再計算されて元に戻ります。

この設計は改ざん耐性だけでなく、「セーブデータが壊れたときの復元」にも役立ちます。履歴の各ステップが物理的にありえない(面1未クリアで面3クリアなど)かどうかをチェックする検証ロジックと組み合わせると、さらに堅牢になります。

サーバー側の検証が必要になるケース

クライアント側の対策は、いずれも「コストを上げる」ものです。決定的な防御にはなりません。次のいずれかに該当する場合は、サーバー側での検証を検討してください。

  • ランキングを公開し、不正スコアが他のプレイヤーに影響する
  • セーブデータが課金アイテムや特典の付与条件になっている
  • オンライン対戦で、セーブデータの値が対戦結果に直結する

サーバー検証の基本的な考え方は、「スコアや進行状況をそのまま信頼せず、プレイの記録(操作ログ・経過時間・取得リソース数など)を送って、サーバー側で再現・検証する」です。これによって、クライアントからどんな値を送ってきても、サーバーが「ありえないプレイ記録」を弾けます。

実装には外部のバックエンドサービスが必要です。FirebaseのFirestoreやRealtimeDatabaseをセキュリティルールと組み合わせる方法、またはVercelやCloudflare WorkersなどのサーバーレスAPIを経由してデータを書き込む方法が、ブラウザゲームと相性がよいです。アソバースのSDKを使ってクラウドセーブに対応したゲームでも、「何を保存するか」「保存前にどう検証するか」の設計は作者側の責任になります。

実装の優先順位と判断の目安

対策を選ぶ際の目安をまとめると、次のようになります。

  • 一人プレイ・スコア非公開、推奨する対策:チェックサムのみ、または無対策でも許容範囲
  • ランキング公開・サーバーなし、推奨する対策:チェックサム+間接的なデータ構造で抑止
  • ランキング公開・不正を確実に弾きたい、推奨する対策:サーバー側での検証が必要
  • 課金・報酬との連動あり、推奨する対策:サーバー検証+専門家への相談を推奨

完全な防御より「大半の人が手軽に改ざんできない状態をつくる」ことを目標に置くと、コストと効果のバランスが取りやすいです。また、対策を実装したとしても、「改ざんされた可能性がある場合はデータをリセットする」という安全なフォールバック処理を忘れずに入れておくことが重要です。保存データが壊れたままゲームが動き続けると、予期しないバグの原因にもなります。

次の行動

チェックサムの実装から始める場合は、保存するJSONの文字列に対して簡単なハッシュ関数(djb2など)を適用する方法が入門として扱いやすいです。ランキング公開を予定しているゲームであれば、設計の早い段階でサーバー検証の要否を判断し、バックエンドの選定を進めてください。アソバースにZIPファイルとして投稿する場合でも、外部のAPIエンドポイントを呼び出す設計は問題なく組み込めます。

参考資料

  • MDN Web Docs「Web Storage API」
  • OWASP「Client-Side Storage Security」
  • Firebase公式ドキュメント「Security Rules」