データ保護

「サーバーを立ててください」が答えにならないチームへ — バックエンドなしのデータ防御

「重要な値はサーバーで判定を」— では、サーバーがなければ

ゲームセキュリティの話は、たいてい同じ一文で終わります。「通貨やスコアのような重要な値はクライアントを信用せず、サーバーが最終判定すべきです」

正しい話です。私たち自身も何度も同じことを書いてきました。

問題はその先です。バックエンドを持たないチームにとって、この助言は実質「いまの構造を作り直してください」と同じです。サーバーを立てるにはサーバー費用、アカウントの仕組み、障害対応、個人情報の取り扱い、そしてそれを維持する人が要ります。シングルプレイ中心のゲームなら、その負担が得られるものを上回ることもあります。

そこでこの記事は別の問いを扱います。サーバーを持たないと決めた状態で、どこまでできて、何は諦めるべきか。

まず正直に:サーバーなしではできないこと

始める前に、はっきりさせておくことがあります。クライアントが最終判定を握っているかぎり、決定的な防御はありません。

ゲームが端末の中で「ゴールド5,000」と判断し、その判断を照合する外部の基準がないなら、時間をかけた攻撃者は結局その値を好きなようにできます。保存形式を変えても、署名を付けても、メモリに隠しても同じです。検証するコードも同じ端末の中にあるからです。

ですからサーバーレスの環境で目標を「防ぐ」に置くと失敗します。現実的な目標は三つです。

  • コストを上げる — セーブファイルをテキストエディタで開く水準から、バイナリを解析する水準へ
  • 痕跡を残す — 改ざんが起きた事実を、後からでも把握できるように
  • 戻せるようにする — 問題が表に出たとき、正常な状態へ復旧する経路を残しておく

この三つだけでも、カジュアルな改ざんのほとんどはふるい落とせます。セーブファイル自体をどう守るかはゲームのセーブファイル改ざんで扱いました。この記事はその次の話です。

サーバーがないときに特によく通る三つ

1. セーブのロールバック — 取り消しボタンがただで手に入る状態

セーブファイルをまるごとコピーしておき、結果が気に入らなければ戻します。

  • ガチャを引き、結果が悪ければ復元して引き直す
  • 消費アイテムを使い、復元して消費をなかったことにする
  • 難所で倒れたら復元してペナルティを消す

この攻撃の厄介なところは、ファイルを改ざんする必要がない点です。正規のセーブを正規に復元するだけなので、整合性検証や暗号化ではふるい落とせません。署名も通ります。そのセーブは本物ですから。

2. 端末時刻の改ざん — 待ち時間をなくす方法

端末の時計を進めれば、時間を消費する設計は崩れます。

  • デイリー報酬を一日に何度も受け取る
  • 建設や育成のタイマーを即座に終わらせる
  • クールタイムをリセットする

System.DateTime.Now は端末の時計を読みます。サーバーがなければ、その時計が正しいか照合する基準がありません。

3. クラウドセーブの競合 — 二台を行き来して有利なほうを選ぶ

クラウドセーブを使うと、端末二台で異なる進行状態が生まれることがあります。どちらを残すか決めなければならず、その決定ルールが利用されます。次の節で扱います。

サーバーなしで使える四つの構造

単調増加カウンターでロールバックを検知する

セーブを保存するたびに1ずつ増える番号を一緒に記録します。そしてこの番号の最大値をセーブとは別の場所に残します。

読み込むときにセーブの番号が記録された最大値より小さければ、戻されたということです。戻ったという事実自体は分かります。

もちろん攻撃者が両方を戻せば通ります。ですからこれは防ぐ手段ではなく、コストを上げる手段です。セーブファイル一つをコピーすれば済んだものが、保存場所を二か所探して一緒に扱う作業になります。

時刻は「巻き戻り」の検知までに使う

最後に観測した時刻を保存しておき、次に起動したときにそれより前なら、時計が戻されたと判断できます。

逆に進んだほうは判別が難しいものです。実際に一日経ったのか時計を一日進めたのか、端末の中では区別する根拠がありません。ここでありがちな失敗は、時刻の巻き戻りを見つけてすぐ制裁することです。海外への移動、サマータイム、時計の自動補正といった正常な理由でも時刻は動きます。

ネットワークをまったく使わないゲームでないなら、信頼できる時刻を時々取得することが最も確実です。全面的なバックエンドではなく時刻だけ確認する程度なら、負担ははるかに小さくなります。

報酬設計を時間依存から進行依存へ移す

最も根本的な解は技術ではなく設計の側にあります。時間が経てば得られる報酬を、プレイすれば得られる報酬に変えれば、時計の改ざんで得るものがなくなります。

すべてのゲームに使える方法ではありません。ただ、サーバーなしで時間ベースの設計を守るのはもともと難しいと知って始めるほうがよいでしょう。

セーブを端末に紐づける

セーブに端末の識別子を一緒に署名しておくと、他人のセーブファイルをそのまま持ってくる方式はふるい落とせます。コミュニティに「完成したセーブファイル」が出回る類型に効きます。

端末の変更とバックアップ復元のシナリオを必ず一緒に設計してください。そうしないと、正常な利用者が端末を替えたときに進行が飛びます。

クラウドセーブの落とし穴 — 競合の解決はあなたの仕事です

ここがサーバーレスのゲームで最も見落とされる点です。

Google のPlay Games Services 保存済みゲームのドキュメントはこの点を明確にしています。端末を複数使う、保存中に接続できない、ゲスト進行とアカウント進行が出会う——こうしたときに競合が起きます。そしてサービスは競合を自動で解決しません。 どちらを残すかはゲームが判断します。

判断材料として提供されるのは ID、名前、説明、最終更新時刻、プレイ時間、カバー画像です。ここでセキュリティ上の問題が一つ出てきます。

プレイ時間と説明は開発者、つまりクライアントが入れる値です。 競合を解決するために「プレイ時間が長いほうを残す」というルールを使うなら、その値を書き換えられる攻撃者に、どちらを選ぶかの権限を渡すことになります。

実務として決めることは次のとおりです。

  • 競合解決のルールを明示的に決める。 決めなければ偶然できたルールが使われ、攻撃者はそれを利用します。
  • クライアントが入れた値ひとつだけで判断しない。 複数の根拠を併せて見るか、利用者に選ばせるほうが安全です。
  • 利用者に選ばせるときは、何を失うかを見せる。 ドキュメントもゲスト進行の競合では利用者に知らせて選ばせるよう勧めています。
  • 正常な利用者のデータを失わせない。 これが最優先です。改ざんを止めようとして正常な進行を消すほうが損害は大きくなります。

具体的な API と最新の挙動は、必ず各プラットフォームの公式ドキュメントで確認してください。プラットフォームの方針はこの記事より速く変わります。

いつサーバーが必要になるか

サーバーなしで持ちこたえることが、いつまでも合理的とはかぎりません。次のうち一つでも当てはまれば、その時期が来ています。

  • ランキングや競争要素があり、一人の改ざんが他の人の体験を損なう。
  • アプリ内課金で得た通貨がゲームの進行に影響する。
  • プレイヤー間の取引、贈り物、ギルドなど、データが人の間を移動する機能がある。
  • 改ざんの事例を確認したが、どこまで広がったか把握する手段がない。
  • 正常な利用者の進行を復旧してほしいという問い合わせに答える根拠がない。

実務では最後の二つが決定的です。サーバーがなければ何が起きたのか分からず、戻してあげることもできません。 改ざんそのものより、この無力さが運用を苦しくします。

全面的なバックエンドでなくてもかまいません。信頼できる時刻、セーブ整合性の記録、異常の兆候の収集といった狭い範囲から始められます。

点検項目

セーブの構造

  • セーブに単調増加する番号があり、その最大値を別の場所に記録している。
  • セーブの整合性検証があり、端末識別子が一緒に紐づいている。
  • 端末変更とバックアップ復元のシナリオが設計に入っている。

時刻

  • 時刻の巻き戻りを検知できる。
  • 検知しても即座に制裁せず、正常な事由を考慮している。
  • 時間依存の報酬があるなら、信頼できる時刻を確認する経路がある。

クラウドセーブ

  • 競合解決のルールが明示的に決まっている。
  • そのルールがクライアントの入れた値ひとつだけに依存していない。
  • 競合時に正常な利用者のデータが保たれる。

運用

  • 改ざんの兆候を後からでも確認できる記録が残る。
  • 上の「いつサーバーが必要になるか」を定期的に見直している。

OZero Security が担う領域と担わない領域

担わない領域

  • サーバーの代わりにはなりません。 クライアントが最終判定を握る構造を私たちが変えることはできません。サーバー判定が必要な値には、やはりサーバーが要ります。
  • クラウドセーブの競合解決ルール、報酬設計、データ復旧の方針は、ゲーム設計と運用の担当です。

担う領域

  • セーブを読み書きするクライアント自体が改ざんされていないかを判断します。実行ファイルのバイナリ改ざん、デバッガ接続とフッキング、エミュレータやルート化のような非信頼の実行環境を識別し、回避の難度を高めます。
  • メモリ改ざんとゲーム速度の操作の試行を、ネイティブレベルで相互検証して検知します。速度の操作は時間依存の設計を狙う代表的な手段です。
  • セーブファイル・PlayerPrefs の改ざん保護と、他の端末のセーブを持ち込むことを防ぐ端末バインディングを提供します。正当な機種変更のために、自分で制御するリセットコールバックがあります。オプションのウェブ時刻確認は、端末の時計を公開の時刻ソースと比較して時計操作の検知を助けます。
  • Pro Add-on と連携すると、疑わしいクライアントのテレメトリを収集し、バックオフィスで運用ポリシーに沿って対応できるよう支援します。サーバーを持たないチームには、これが「何が起きたのかを知る」最初の経路になることもあります。

検証のロジックを C# の外、Native C++ の層に置けば、検証コード自体を止めることが別の作業になります。サーバーがない環境での「コストを上げる」目標にあたる部分です。

結論:防げないと分かったうえで設計する

サーバーレスのゲームにおけるデータ保護は、完全な防御を作る仕事ではありません。それは構造的に無理です。

代わりにこう考えてください。カジュアルな改ざんはふるい落とし、本気の攻撃はコストを上げ、何が起きたかは分かるようにし、正常な利用者には戻してあげられるように。 ここまでがサーバーなしで可能な範囲です。

そしてその範囲を越えた瞬間 — ランキングができたり、課金通貨が進行に影響したり、プレイヤー間でデータが動き始めたら — サーバーは選択ではなく必要になります。その線を先に知っているだけでも、判断は速くなります。

次のステップ

  1. 保護範囲を確認する — プラットフォーム別の対応仕様と、プラン(Standard / Pro)ごとの防御範囲を確認できます。
  2. すぐに統合を始める — インポートと設定の手順は統合ガイドにあります。
  3. 技術的な相談 — サーバーのない構成でどこまで可能かお問い合わせください。

サーバーがなくてもクライアントの整合性は検証できます — OZero Security。

あわせて読みたい