質問: ### 前提・実現したいこと スマホゲームのランキングサーバのチート対策を実現しようと考えています。具体的には、ユーザがクライアント側でゲーム(例えばシューティングゲーム)を行い、ゲーム終了時のスコアを `{ "user_id": 123456789, "score": 34567}` のようなパラメータでサーバに送信してもらいます。ユーザがゲームをするクライアントはブラウザ・iOS・Androidの3つに対応させようとしています。 ### 調査したこと スコアを送信する際に、通信データを偽装することでスコアを異常に高くするなどのチートが可能になってしまいます。チート対策の分かり易い資料として、以下のスライドがあります。 > > 一般的なチートの手法と対策について > > > > > この資料では通信データ偽装への対策としてハッシュを用いる方法が解説されています。 1. クライアント側で「送信データ」のハッシュ値を生成 2. 「送信データ」とハッシュ値をペアで送信 3. サーバ側で「送信データ」からハッシュ値を生成し、クライアントから送られてきたハッシュ値と一致することを確認 といった方法です。 ### 疑問 上記の方法を用いると、**「クライアントで行っているハッシュ値生成のアルゴリズムを秘匿できれば」**という条件付きで通信データ偽装を防ぐ事ができるかと思います。しかし、ブラウザやAndroidではユーザがコードを見ることが可能なので、どんな処理でハッシュ値を生成しているか分かってしまいます。これを防ぐには、どのようにすればよいのでしょうか?難読化で処理を見にくくするしかないのでしょうか? 上記のスライドの方法以外でも、定石の手法などがありましたら教えて頂きたく思います。ふわふわとした質問になってしまいましたが、よろしくお願いいたします。
回答: 質問文の記事はバイナリファイル化されたゲームが基準になっていますので、 ブラウザーゲームでは役に立たないでしょう。 ブラウザゲーム時代のチートとセキュリティ この辺からわかるように、ユーザーには権限は与えないのが一番の対策です。 まぁ、パケットをインターセプトする輩をJavaScriptで止める方法はないと考えた方が良いでしょうね。 話は少し変わりますが、将棋では棋譜、麻雀では牌譜と言うものがあることはご存知でしょうか? これは元々感想戦という勝負時の取捨選択の結果を書き起こしたものですが、 コンピュータ上で再現されたこれらのゲームはテキストファイルとして書き起こしてログとしても使う事が出来ます。 実際にネット将棋や麻雀のサーバーではこの棋譜や牌譜を保存することで、 対局してないのに勝利するチートや、手牌を改ざんして役満をあがり続ける行為への対策としています。 上記を応用して、**再現可能なログファイル**にまでゲームを落とし込む事ができれば、 ある程度のチートは防ぐ事が可能です。 上記の手法を応用して、例えば対戦格闘ゲームやシューティングゲームは、 時間軸というタイミングを伴った完全情報ゲームに置き換える事が可能です。 以下は余談ですが、RPGやすごろく等の乱数も制御が可能です。 例えばRPGでは電源を入れた瞬間からの時間で乱数が決まる事を利用したテクニックがいくつもあります。 (特定の場所でセーブして、電源入れながら下を押し続けて戦闘に入りAボタン押しっぱなしにすると会心の一撃が必ず出てボスを倒せるとかね...) いただきストリート2というゲームでは超長い乱数表が既に存在しており、何度リセットしても必ず同じサイコロの出目の順番でゲームが進行する仕組みになっています。 その中でも風来のシレンと同じ仕組みを構築することをおすすめします。 フロアに降り立った時、その瞬間の主人公の状態、フロアや敵の状態、乱数表が全て保存されます。 主人公がそのフロアの冒険中、毎ターン行った操作のみをログファイルとして作成し、セーブデータに吐き出します。 もし電顕を落とした場合、後からロードすると、フロアに降り立った後の冒険をログファイルを元に書き出して再現します。 なので一定数以上同じフロアに留まろうとすると、地震や風が吹いてそのフロアから追い出されてしまう仕組みなのですね。 (まぁこれ自体は風来のシレンのセーブ用RAMの少なさを解決するテクニックだったわけですが...) クライアントから送信されたログファイルと、サーバー上にあるゲーム開始時のステータス・乱数テーブルの3つさえあれば、 そのプレイヤーが取りうる理論上行える最善のプレイ以上の結果は出せなくなります。