什么是阻止人们破解基于PHP的Flash游戏高分表的最佳方法

时间:2008-09-16 16:01:28

标签: php actionscript-3 security actionscript actionscript-2

我说的是没有上限分数的动作游戏,无法通过重播动作来验证服务器上的分数。

我真正需要的是Flash / PHP中可能的最强加密,以及防止人们通过我的Flash文件调用PHP页面的方法。我曾经尝试过一些简单的方法,可以对单个分数进行多次调用并完成校验和/斐波纳契序列等,并且还使用Amayeta SWF加密对SWF进行混淆,但最终都被黑客攻击。

感谢StackOverflow的回复,我现在从Adobe发现了更多信息 - http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps_12.htmlhttps://github.com/mikechambers/as3corelib - 我认为我可以使用它来进行加密。不知道这会让我在CheatEngine附近。

如果它们不同,我需要知道AS2和AS3的最佳解决方案。

主要问题似乎是TamperData和LiveHTTP标题,但我知道还有更高级的黑客工具 - 比如CheatEngine(感谢Mark Webster)

18 个答案:

答案 0 :(得分:414)

答案 1 :(得分:25)

你可能会问错误的问题。你似乎专注于人们用来在高分榜上进行游戏的方法,但阻止特定方法只是到目前为止。我对TamperData没有经验,所以我不能说出来。

您应该问的问题是:“我如何验证提交的分数是否有效且真实?”具体方法是依赖游戏。对于非常简单的益智游戏,您可以发送得分以及特定的起始状态和导致结束状态的移动顺序,然后使用相同的移动在服务器端重新运行游戏。确认所述分数与计算得分相同,只有在匹配时才接受分数。

答案 2 :(得分:18)

一种简单的方法是提供高分值的加密哈希以及自己的分数。例如,通过HTTP GET发布结果时: 的 http://example.com/highscores.php?score=500&checksum=0a16df3dc0301a36a34f9065c3ff8095

计算此校验和时,应使用共享密钥;这个秘密永远不应该通过网络传输,但应该在PHP后端和flash前端内进行硬编码。上面的校验和是通过将字符串“ secret ”添加到分数“ 500 ”并通过md5sum运行来创建的。

尽管该系统将阻止用户发布任意分数,但它不会阻止“重放攻击”,其中用户重新发布先前计算的分数和散列组合。在上面的示例中,得分500将始终生成相同的哈希字符串。通过在要散列的字符串中包含更多信息(例如用户名,时间戳或IP地址),可以减轻某些风险。虽然这不会阻止重放数据,但它可以确保一组数据一次只对单个用户有效。

为防止发生任何重播攻击,必须创建某种类型的质询 - 响应系统,例如:

  1. Flash游戏(“客户端”)在没有参数的情况下执行 http://example.com/highscores.php 的HTTP GET。此页面返回两个值:随机生成的 salt 值,以及该salt值与共享密钥组合的加密哈希值。此salt值应存储在待处理查询的本地数据库中,并且应该有一个与之关联的时间戳,以便它可以在一分钟后“过期”。
  2. Flash游戏将salt值与共享密钥组合在一起,并计算哈希值以验证它是否与服务器提供的哈希值匹配。此步骤对于防止用户篡改salt值是必要的,因为它验证了salt值是否实际由服务器生成。
  3. Flash游戏将salt值与共享密钥,高分值以及任何其他相关信息(昵称,ip,时间戳)相结合,并计算哈希值。然后,它通过HTTP GET或POST将此信息以及盐值,高分和其他信息发送回PHP后端。
  4. 服务器以与客户端相同的方式组合收到的信息,并计算哈希以验证它是否与客户端提供的哈希匹配。然后,它还验证salt值是否仍然有效,如挂起查询列表中所列。如果这两个条件都为真,则将高分写入高分表并将签名的“成功”消息返回给客户端。它还会从挂起的查询列表中删除salt值。
  5. 请注意,如果用户可以访问共享密码,则上述任何技术的安全性都会受到影响

    作为替代方案,通过强制客户端通过HTTPS与服务器通信,并确保客户端预先配置为仅信任由特定证书颁发机构签名的证书,可以避免某些此类来回有权访问。

答案 3 :(得分:11)

我喜欢tpqf所说的,但是在发现作弊行为时,不是禁用某个帐户,而是实施蜜罐,这样每当他们登录时,他们就会看到他们的黑客攻击分数,并且从不怀疑他们被标记为巨魔。谷歌的“phpBB MOD Troll”,你会看到一个巧妙的方法。

答案 4 :(得分:4)

我做了一些解决方法......我有一个得分,其中得分增加(你总是获得+1分)。首先,我开始计算随机数(假设是14),当我显示分数时,只显示得分减去14.这是如此,如果破解者正在寻找20的例子,他们将找不到它(它将在记忆中34岁)。其次,因为我知道下一点应该是什么......我使用adobe crypto库来创建下一个应该的哈希值。当我必须增加分数时,我检查增量分数的散列是否等于散列应该是。如果饼干改变了记忆中的点数,则哈希值不相等。我执行一些服务器端验证,当我从游戏和PHP获得不同点时,我知道涉及作弊。这是我的代码片段(我正在使用Adobe Crypto libraty MD5类和随机加密盐.callPhp()是我的服务器端验证)

private function addPoint(event:Event = null):void{
            trace("expectedHash: " + expectedHash + "  || new hash: " + MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt) );
            if(expectedHash == MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt)){
                SCORES +=POINT;
                callPhp();
                expectedHash = MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt);
            } else {
                //trace("cheat engine usage");
            }
        }

使用这种技术+ SWF obfustication,我能够阻止破解者。此外,当我将分数发送到服务器端时,我使用自己的小型加密/解密功能。像这样的东西(不包括服务器端代码,但你可以看到算法并用PHP编写):

package  {

    import bassta.utils.Hash;

    public class ScoresEncoder {

        private static var ranChars:Array;
        private static var charsTable:Hash;

        public function ScoresEncoder() {

        }

        public static function init():void{

            ranChars = String("qwertyuiopasdfghjklzxcvbnm").split("")

            charsTable = new Hash({
                "0": "x",
                "1": "f",
                "2": "q",
                "3": "z",
                "4": "a",
                "5": "o",
                "6": "n",
                "7": "p",
                "8": "w",
                "9": "y"

            });

        }

        public static function encodeScore(_s:Number):String{

            var _fin:String = "";

            var scores:String = addLeadingZeros(_s);
            for(var i:uint = 0; i< scores.length; i++){
                //trace( scores.charAt(i) + " - > " + charsTable[ scores.charAt(i) ] );
                _fin += charsTable[ scores.charAt(i) ];
            }

            return _fin;

        }

        public static function decodeScore(_s:String):String{

            var _fin:String = "";

            var decoded:String = _s;

            for(var i:uint = 0; i< decoded.length; i++){
                //trace( decoded.charAt(i) + " - > "  + charsTable.getKey( decoded.charAt(i) ) );
                _fin += charsTable.getKey( decoded.charAt(i) );
            }

            return _fin;

        }

        public static function encodeScoreRand(_s:Number):String{
            var _fin:String = "";

            _fin += generateRandomChars(10) + encodeScore(_s) + generateRandomChars(3)

            return _fin;
        }

        public static function decodeScoreRand(_s:String):Number{

            var decodedString:String = _s;
            var decoded:Number;

            decodedString = decodedString.substring(10,13);         
            decodedString = decodeScore(decodedString);

            decoded = Number(decodedString);

            return decoded;
        }

        public static function generateRandomChars(_length:Number):String{

            var newRandChars:String = "";

            for(var i:uint = 0; i< _length; i++){
                newRandChars+= ranChars[ Math.ceil( Math.random()*ranChars.length-1 )];
            }

            return newRandChars;
        }

        private static function addLeadingZeros(_s:Number):String{

            var _fin:String;

            if(_s < 10 ){
                 _fin = "00" + _s.toString();
            }

            if(_s >= 10 && _s < 99 ) {
                 _fin = "0" + _s.toString();
            }

            if(_s >= 100 ) {
                _fin = _s.toString();
            }           

            return _fin;
        }


    }//end
}

然后我将变量与其他假vars一起发送,它只是在途中迷失了......对于小型Flash游戏来说,这是很多工作,但是涉及到奖品时,有些人会变得贪婪。如果您需要任何帮助,请给我写一个PM。

干杯,Ico

答案 5 :(得分:4)

在接受的答案中,tqbf提到您可以对记分变量进行记忆搜索(“我的分数为666,所以我在内存中查找数字666”)。

有一种解决方法。我在这里上课:http://divillysausages.com/blog/safenumber_and_safeint

基本上,您有一个对象来存储您的分数。在setter中,它将您传递的值乘以随机数(+和 - ),并在getter中将保存的值除以随机乘数以获得原始值。这很简单,但有助于停止内存搜索。

另外,请查看PushButton引擎背后的一些人的视频,他们谈论了一些可以打击黑客攻击的不同方法:http://zaa.tv/2010/12/the-art-of-hacking-flash-games/。他们是课堂背后的灵感。

答案 6 :(得分:3)

使用已知(私有)可逆密钥进行加密将是最简单的方法。我不是全部都在AS所以我不确定那里有什么样的加密提供商。

但您可以包含游戏长度(再次加密)和点击次数等变量。

这样的所有东西都可以进行逆向工程,所以可以考虑扔掉一堆垃圾数据,让人们远离气味。

编辑:在某些PHP会话中也可能值得一试。当他们点击开始游戏时开始会话,并且(如此帖子的评论所示)记录时间。当他们提交分数时,你可以检查他们是否实际上有一个开放的游戏,他们没有提交太快或太大的分数。

可能需要制定一个标量才能看出每秒/分钟的最高得分是多少。

这些都不是不可避免的,但它们有助于在Flash中找到一些人们可以看到它的逻辑。

答案 7 :(得分:3)

您无法信任客户返回的任何数据。验证需要在服务器端执行。我不是游戏开发者,但我做的是商业软件。在这两种情况下,都可以涉及金钱,人们会破坏客户端的混淆技术。

可能会定期将数据发送回服务器并进行一些验证。不要专注于客户端代码,即使这是您的应用程序所在的位置。

答案 8 :(得分:3)

根据我的经验,这最好是作为社会工程问题而不是编程问题。而不是专注于使其不可能作弊,而是通过消除作弊的动机来集中精力使其变得无聊。例如,如果主要激励是公开可见的高分,只是在显示高分时延迟,可以通过消除作弊者的正面反馈循环来显着减少作弊。

答案 9 :(得分:2)

我通常会在高分条目中包含游戏会话的“幽灵数据”。因此,如果我正在制作赛车游戏,我会包含重播数据。你经常会有重播数据的重播数据或幽灵赛车功能(与你的上一场比赛比赛,或者在排行榜上与队友#14的鬼魂对战)。

检查这些是非常体力劳动,但如果目标是验证比赛中的前10个条目是否合法,这可能是其他人已经指出的安全措施的有用补充。

如果我们的目标是保持高分榜在线,直到时间的结束,而不需要任何人看到它们,这不会带给你太多。

答案 10 :(得分:2)

只有将所有游戏逻辑保留在服务器端,才能在不知道用户的情况下在内部存储得分。出于经济和科学的原因,人类不能将这一理论应用于除回合制之外的所有游戏类型。对于例如将物理学保持在服务器端是计算上昂贵的并且很难以手的速度响应。甚至可能,在下棋时,任何人都可以将AI国际象棋游戏与对手相匹配。因此,更好的多人游戏也应该包含按需创意。

答案 11 :(得分:2)

我认为最简单的方法是每次游戏注册要添加的分数然后对其进行编码,打包并将其作为字符串发送到php脚本时,调用RegisterScore(得分)等函数。 php脚本会知道如何正确解码它。这将直接停止任何调用php脚本,因为任何强制分数的尝试都会导致解压缩错误。

答案 12 :(得分:2)

一种新的流行街机模式的方式是它将数据从闪存发送到php,返回闪存(或重新加载),然后返回到php。这允许您执行任何您想要比较数据以及绕过后期数据/解密黑客等的操作。这样做的一种方法是将2个随机值从php分配到闪存中(即使运行实时闪存数据采集器也无法抓取或看到),使用数学公式将分数与随机值相加然后使用相同的公式,以反转它,看看当它最终进入最后的PHP时,得分是否匹配。这些随机值永远不可见,并且它也会发生交易次数,如果它超过几秒钟,那么它也会将其标记为作弊,因为它假定您已停止发送以试图找出随机值或运行通过某种类型的密码返回可能的随机值以与分数值进行比较。

如果您问我,这似乎是一个非常好的解决方案,有人看到使用此方法有任何问题吗?或者可能的方法呢?

答案 13 :(得分:2)

您正在谈论所谓的“客户信任”问题。因为客户端(以现金形式,在浏览器中运行的SWF)正在做一些它旨在做的事情。保存高分。

问题是您要确保“保存分数”请求来自您的Flash影片,而不是某些任意HTTP请求。对此可能的解决方案是在请求时使用flasm将服务器生成的令牌编码到SWF中,该请求必须伴随保存高分的请求。一旦服务器保存该分数,该令牌就会过期,不能再用于请求。

这样做的缺点是用户只能在每次加载flash电影时提交一个高分 - 你必须强制他们刷新/重新加载SWF才能再次播放新的乐谱。

答案 14 :(得分:2)

没有办法让它完全不可攻击,因为很容易反编译SWF,熟练的开发人员黑客可以跟踪你的代码并找出如何绕过你可能使用的任何加密系统。

如果你只是想通过使用像TamperData这样的简单工具来阻止孩子作弊,那么你可以生成一个加密密钥,你在启动时传递给SWF。然后使用http://code.google.com/p/as3crypto/之类的东西加密高分,然后再将其传回PHP代码。然后在将其存储在数据库中之前在服务器端解密。

答案 15 :(得分:2)

每当您的高分系统基于Flash应用程序通过网络发送未加入/未签名的高分数据这一事实时,可以截获并操纵/重放。答案如下:加密(正确!)或加密签名高分数据。这至少会让人们更难破解你的高分系统,因为他们需要从你的SWF文件中提取密钥。许多人可能会在那里放弃。另一方面,只需要一个单独的人来提取密钥并将其发布到某个地方。

真正的解决方案涉及Flash应用程序和高分数据库之间的更多通信,以便后者可以验证给定分数是否有些现实。这可能很复杂,取决于你有什么样的游戏。

答案 16 :(得分:1)

实际上不可能达到你想要的效果。 Flash应用程序的内部总是可以部分访问,特别是当您知道如何使用CheatEngine之类的内容时,这意味着无论您的网站和浏览器与服务器通信的安全程度如何,它仍然是相对的很容易克服。

答案 17 :(得分:1)

通过AMFPHP与后端进行通信可能是个好主意。它应该阻止至少懒惰的人尝试通过浏览器控制台推送结果。