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

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

感谢 StackOverflow 的回复,我现在从 Adob​​e 找到了更多信息 - http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps_12.htmlhttps://github.com/mikechambers/as3corelib - 我想我可以用它来加密。但不确定这是否能让我绕过 CheatEngine。

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

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

有帮助吗?

解决方案

这是网络游戏和竞赛中的一个经典问题。您的 Flash 代码与用户一起决定游戏的得分。但用户不受信任,Flash 代码在用户的计算机上运行。你是索尔。您无法阻止攻击者伪造高分:

  • Flash 比您想象的更容易进行逆向工程,因为字节码有详细记录并描述了高级语言(Actionscript)——当您发布 Flash 游戏时,您就发布了源代码,无论您是知道与否。

  • 攻击者控制Flash解释器的运行时内存,因此任何知道如何使用可编程调试器的人都可以随时更改任何变量(包括当前分数),或更改程序本身。

针对您的系统的最简单的攻击是通过代理运行游戏的 HTTP 流量,捕获高分保存,并以更高的分数重玩它。

您可以尝试通过将每个高分保存绑定到游戏的单个实例来阻止此攻击,例如通过在游戏启动时向客户端发送加密令牌,这可能如下所示:

hex-encoding( AES(secret-key-stored-only-on-server, timestamp, user-id, random-number))

(您也可以使用会话 cookie 达到相同的效果)。

游戏代码通过高分保存将此令牌回显给服务器。但攻击者仍然可以再次启动游戏,获取令牌,然后立即将该令牌粘贴到重播的高分保存中。

因此,接下来您不仅要提供令牌或会话 cookie,还要提供高分加密会话密钥。这将是一个 128 位 AES 密钥,本身使用硬编码到 Flash 游戏中的密钥进行加密:

hex-encoding( AES(key-hardcoded-in-flash-game, random-128-bit-key))

现在,在游戏发布高分之前,它会解密高分加密会话密钥,因为您将高分加密会话密钥解密密钥硬编码到 Flash 二进制文件中。您使用此解密密钥以及高分的 SHA1 哈希值来加密高分:

hex-encoding( AES(random-128-bit-key-from-above, high-score, SHA1(high-score)))

服务器上的 PHP 代码检查令牌以确保请求来自有效的游戏实例,然后解密加密的高分,检查以确保高分与高分的 SHA1 匹配(如果您跳过此步骤) ,解密只会产生随机的,可能非常高的分数)。

因此,现在攻击者反编译您的 Flash 代码并快速找到 AES 代码,该代码非常突出,尽管即使没有,也可以通过内存搜索和跟踪器在 15 分钟内找到它(“我知道我这个游戏的分数是 666,所以让我们在内存中找到 666,然后捕获任何触及该值的操作 --- 哦,看,高分加密代码!”)。有了会话密钥,攻击者甚至不必运行 Flash 代码;她获取游戏启动令牌和会话密钥,并可以发回任意高分。

现在,大多数开发人员都会放弃——通过以下方式与攻击者进行几个月的纠缠:

  • 使用 XOR 运算加扰 AES 密钥

  • 用计算密钥的函数替换密钥字节数组

  • 在整个二进制文件中散布虚假密钥加密和高分帖子。

这基本上都是浪费时间。不用说,SSL 也不会帮助你;当两个 SSL 端点之一是邪恶的时,SSL 无法保护您。

以下是一些实际上可以减少高分欺诈的事情:

  • 需要登录才能玩游戏,让登录生成会话 cookie,并且不允许在同一会话上启动多个未完成的游戏,或同一用户的多个并发会话。

  • 拒绝持续时间短于曾经玩过的最短真实游戏的游戏会话的高分(对于更复杂的方法,尝试“隔离”持续时间低于平均游戏持续时间 2 个标准差的游戏会话的高分)。确保您在服务器端跟踪游戏持续时间。

  • 拒绝或隔离只玩过一次或两次游戏的登录的高分,以便攻击者必须为他们创建的每次登录生成看起来合理的游戏玩法的“纸质记录”。

  • “心跳”会在游戏过程中得分,以便您的服务器在一场游戏的生命周期内看到分数的增长。拒绝不遵循合理分数曲线的高分(例如,从 0 跳到 999999)。

  • 游戏过程中的“快照”游戏状态(例如,弹药量、关卡中的位置等),您可以稍后将其与记录的临时分数进行协调。您甚至不必一开始就有办法检测这些数据中的异常;你只需要收集它,然后如果事情看起来可疑,你可以回去分析它。

  • 禁用任何未通过一项安全检查的用户的帐户(例如,提交未通过验证的加密高分)。

但请记住,您在这里只是阻止高分欺诈。有 没有什么 你可以采取措施来防止如果。如果你的游戏中存在金钱风险,那么有人会击败你想出的任何系统。目的不是为了 停止 这次攻击;这是为了让攻击比仅仅真正擅长游戏并击败它更加昂贵。

其他提示

你可能问错了问题。您似乎专注于人们用来提高高分列表的方法,但阻止特定方法只能到此为止。我没有 TamperData 方面的经验,所以我无法谈论这一点。

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

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

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

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

阻止 任何 为了避免发生重放攻击,必须创建某种类型的质询-响应系统,如下所示:

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

请记住,如果用户可以访问共享秘密,则上述任何技术的安全性都会受到损害

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

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

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

有办法解决这个问题。我在这里上课: http://divillysausages.com/blog/safenumber_and_safeint

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

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

我做了一种解决方法...我有一个分数递增的给定(你总是得到+1分数)。首先,我开始从随机 num (比方说 14 )开始计数,当我显示分数时,只显示分数 var - 14 。因此,如果破解者正在寻找 20,他们将找不到它(内存中将是 34)。其次,因为我知道下一步应该是什么......我使用 adobe crypto 库来创建下一点的哈希值 应该. 。当我必须增加分数时,我检查增加分数的哈希值是否等于应有的哈希值。如果破解者更改了内存中的点,则哈希值不相等。我执行了一些服务器端验证,当我从游戏和 PHP 中得到不同的分数时,我知道其中涉及作弊。这是我的代码片段(我正在使用 Adob​​e 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 混淆,我能够阻止破解者。另外,当我将分数发送到服务器端时,我使用自己的小型加密/解密函数。像这样的东西(不包括服务器端代码,但你可以看到算法并用 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
}

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

干杯,伊科

使用已知(私有)可逆密钥进行加密将是最简单的方法。我不太了解 AS,所以我不确定有哪些类型的加密提供商。

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

所有的事情都是这样的 是逆向工程,所以考虑扔进一堆垃圾数据来让人们失去踪迹。

编辑:也许也值得参加一些 PHP 会议。当他们单击“开始游戏”时开始会话并(正如本文的评论所述)记录时间。当他们提交分数时,您可以检查他们是否确实有一场开放的比赛,并且他们没有提交太快或太大的分数。

也许值得计算出一个标量来看看每秒/每分钟的最高得分是多少。

这些事情都不是不可规避的,但在人们可以看到的Flash中添加一些逻辑会有所帮助。

根据我的经验,最好将其视为社会工程问题而不是编程问题。与其专注于让作弊变得不可能,不如专注于通过消除作弊动机来让作弊变得无聊。例如,如果主要动机是公开可见的高分,那么只需推迟显示高分的时间就可以通过消除作弊者的正反馈循环来显着减少作弊行为。

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

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

每当您的高分系统基于 Flash 应用程序通过网络发送未加密/未签名的高分数据时,这些数据都可以被拦截和操纵/重播。答案由此而来:加密(体面!)或对高分数据进行加密签名。这至少使人们更难破解您的高分系统,因为他们需要从您的 SWF 文件中提取密钥。很多人可能会直接放弃。另一方面,只需要一个人提取密钥并将其发布到某个地方即可。

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

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

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

您谈论的是所谓的“客户信任”问题。因为客户端(即在浏览器中运行的 SWF)正在执行其设计目的。保存高分。

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

这样做的缺点是,用户每次加载 Flash 影片时只能提交一个高分 - 您必须强制他们刷新/重新加载 SWF,然后才能再次播放以获得新分数。

我通常会在高分条目中包含游戏会话的“幽灵数据”。因此,如果我正在制作赛车游戏,我会包含重播数据。您通常已经拥有用于重播功能或幽灵赛车功能的重播数据(与您的上一场比赛比赛,或与排行榜上第 14 号家伙的幽灵比赛)。

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

如果目标是将高分列表保留在网上直到时间结束而无需任何人查看,那么这不会给您带来太多。

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

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

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

只有保持 所有游戏逻辑都在服务器端 它还在用户不知情的情况下在内部存储分数。出于经济和科学的原因,人类无法将这一理论应用于除回合制游戏之外的所有游戏类型。例如将物理保留在服务器端的计算成本很高,并且很难像手速那样做出响应。甚至有可能,在下棋时任何人都可以将人工智能国际象棋玩法与对手进行匹配。因此,更好 多人游戏 还应包含按需创意。

想要达到自己想要的效果其实是不太可能的。Flash 应用程序的内部结构始终是部分可访问的,尤其是当您知道如何使用诸如 作弊引擎, ,这意味着无论您的网站和浏览器<->服务器通信有多安全,克服它仍然相对容易。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top