ダーク/ライト切り替え

【Unity】セーブデータの改ざんやチート対策を考えてみる

投稿日2023-03-23

この記事は1年以上前に投稿されたものです

Picture of the logo


目次

ゲーム開発者にとって、チートは永遠の悩みです。どんなに対策しても開発者とチーターは「いたちごっこ」です。今回は初歩的な手段ではありますが、CRCやSHA256といった技術を使ってデータの改ざん、チート行為を検出する方法を紹介します。

# CRC、SHA256について

CRCやSHA256は、データの改変や誤り検知を行うための手法です。

# CRCとは

CRC(Cyclic Redundancy Check)は、送信されたデータに対して剰余を計算して、その結果を誤り検知のための冗長情報として付加することで、受信側での誤り検知を行います。CRCにはいくつかの種類があり、16ビットのCRC16や32ビットのCRC32が一般的に使われています。

# SHA256とは

一方、SHA256は、データの改変を検知するためのハッシュ関数の1つで、入力されたデータから256ビットの固定長の値を生成します。SHA256は、同じデータに対しては必ず同じ値を生成するので、データの改変を検知するために利用されます。SHA256は、セキュリティの強化が必要な場合にも利用されます。

# 実際にコードを書いてみる

Firebaseなどに保存する際データに改変が無いか検出する簡単なサンプルコードを紹介します。

# CRCを用いたチート検出

using System.Security.Cryptography;
using UnityEngine;

public class SaveData
{
    // セーブデータの内容を保持するクラス
    public int highScore;
    public int coin;
    public int level;

    // セーブデータの内容を文字列化してCRC32ハッシュを計算する関数
    public uint CalculateCRC()
    {
        string saveString = highScore.ToString() + coin.ToString() + level.ToString();
        byte[] saveBytes = System.Text.Encoding.UTF8.GetBytes(saveString);
        uint crc = Crc32Algorithm.Compute(saveBytes);
        return crc;
    }

    // セーブデータを保存する関数
    public void Save()
    {
        // セーブデータを文字列化してCRC32ハッシュを計算する
        uint crc = CalculateCRC();

        // CRC32ハッシュをセーブデータに加えてFirebaseに保存する
        // (省略)
    }

    // セーブデータを読み込んでCRC32ハッシュを検証する関数
    public bool LoadAndVerify()
    {
        // Firebaseからセーブデータを読み込む
        // (省略)

        // セーブデータの内容を文字列化してCRC32ハッシュを計算する
        uint crc = CalculateCRC();

        // Firebaseから読み込んだCRC32ハッシュと計算したCRC32ハッシュを比較する
        uint savedCrc = (uint)loadedData["crc"];
        if (crc != savedCrc)
        {
            // CRC32ハッシュが一致しない場合は改変が検出されたと判断する
            Debug.Log("セーブデータが改変されています!");
            return false;
        }

        // セーブデータの内容を読み込む
        highScore = (int)loadedData["highScore"];
        coin = (int)loadedData["coin"];
        level = (int)loadedData["level"];

        return true;
    }
}

上記の例では、セーブデータの内容を文字列化してCRC32ハッシュを計算し、Firebase等に保存するときにそのハッシュ値も保存しています。そしてセーブデータを読み込むときに、読み込んだデータから再度CRC32ハッシュを計算し、保存されているハッシュ値と比較して一致しない場合は改変が検出されたと判断するという流れになっています。

# SHA256を用いたチート検出

using System.Security.Cryptography;
using UnityEngine;

public class SaveData
{
    // セーブデータの内容を保持するクラス
    public int highScore;
    public int coin;
    public int level;

    // セーブデータの内容を文字列化してSHA256ハッシュを計算する関数
    public string CalculateSHA256()
    {
        string saveString = highScore.ToString() + coin.ToString() + level.ToString();
        byte[] saveBytes = System.Text.Encoding.UTF8.GetBytes(saveString);
        SHA256 sha256 = SHA256.Create();
        byte[] hashBytes = sha256.ComputeHash(saveBytes);
        string hashString = System.Convert.ToBase64String(hashBytes);
        return hashString;
    }

    // セーブデータを保存する関数
    public void Save()
    {
        // セーブデータを文字列化してSHA256ハッシュを計算する
        string hashString = CalculateSHA256();

        // SHA256ハッシュをセーブデータに加えてFirebaseに保存する
        // (省略)
    }

    // セーブデータを読み込んでSHA256ハッシュを検証する関数
    public bool LoadAndVerify()
    {
        // Firebaseからセーブデータを読み込む
        // (省略)

        // セーブデータの内容を文字列化してSHA256ハッシュを計算する
        string hashString = CalculateSHA256();

        // Firebaseから読み込んだSHA256ハッシュと計算したSHA256ハッシュを比較する
        string savedHashString = (string)loadedData["sha256"];
        if (hashString != savedHashString)
        {
            // SHA256ハッシュが一致しない場合は改変が検出されたと判断する
            Debug.Log("セーブデータが改変されています!");
            return false;
        }

        // セーブデータの内容を読み込む
        highScore = (int)loadedData["highScore"];
        coin = (int)loadedData["coin"];
        level = (int)loadedData["level"];

        return true;
    }
}

上記の例では、セーブデータの内容を文字列化してSHA256ハッシュを計算し、Firebase等に保存するときにそのハッシュ値も保存しています。そしてセーブデータを読み込むときに、読み込んだデータから再度SHA256ハッシュを計算し、保存されているハッシュ値と比較して一致しない場合は改変が検出されたと判断するという流れになっています。

# さいごに

これらの手法は、ゲームアプリ開発においてセーブデータの改変を防止するために利用されることがあります。ゲームアプリでは、ユーザーがセーブデータを改変することで不正なアイテムやスコアを入手することができます。そのため、セーブデータにCRCやSHA256のような認証情報を追加することで、改変を検知し、不正行為を防止することができます。

ただし、完全に改変を防ぐことはできないため、セーブデータの暗号化やセキュリティ強化など、より高度なセキュリティ対策が必要になる場合もあります。また、セーブデータの改変を検知するための認証情報を保存すること自体が、攻撃者に対してセーブデータの改変を容易にする可能性もあるため、セキュリティ対策の考え方や実装方法には慎重になる必要があります。

これらは初歩的な技術の紹介であり、これらの情報により生じたいかなる損害につきましても当方では責を負いかねますので予めご了承ください。






関連記事

Unity】一枚のイメージ画像を縦横のタイル状に分割する方法

blog

UnityのUGUIを使用して、一枚のイメージ画像を縦横に分割して表示する方法を紹介します。

UnityでFirebase Storeからデータを読み書きする

blog

FirebaseのFireStoreのデータをUnityから読み書きする手順を紹介します。入門レベル。

Unityで端末情報、IPアドレスを取得する方法

blog

Unityにて端末固有情報などをC#コードから取得する方法をまとめました。

【初心者】Unityでリンク先のウェブサイトを開く方法【備忘録】

blog

Unityからウェブサイトを開く方法を簡単に紹介します。初心者向け、備忘録

Firebase AuthentificationでEmailアカウントと匿名アカウントを実装する

blog

今回はFirebase Authentificationを使ってUnityに匿名認証、メール認証を実装する手順を紹介します。

【Unity】文字列に禁止ワードが含まれているかチェックをする方法

blog

Unityで下品な単語など望ましくない言葉が含まれていないかをチェックする方法を紹介します

Unityでモザイク処理をする方法

blog

今回はUnityで画像にモザイク処理を掛ける方法を紹介します。標準機能では用意されていないようなのでカスタムシェーダーで実装します。

FirebaseStorageからUnityへファイルを読み込み、Resourcesに保存する

blog

UnityでFIREBASEのStorageサービスから画像ファイルをダウンロードしてシーン上に表示、保存するまでの簡単な手順紹介です。

UnityでSNSシェアボタンを実装してみた(NativeShare)【Unity6対応】

blog

UnityアプリにSNSシェアボタンを手軽に実装する事が出来るアセット[NativeShare](https://github.com/yasirkula/UnityNativeShare)を最新のUnity6に実装して、実際にandroid実機で動かすまでの手順を備忘録も兼ねて書き残しておこうと思います。X(旧Twitter)などへのシェア機能を実装してみたい方は参考にしてみてください。

【gRPC】VSCODEとDotNetでgRPC環境を構築してみる

blog

Visual StudioではなくVSCODE上でgRPC環境の構築を簡潔させます。今回は初歩的な開通テストなのでHTTPS化はしません。


スポンサーリンク

このサイトをシェアする