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

我真正需要的是在Flash/PHP中最强的加密,以及一种防止人们调用PHP页面而不是通过我的Flash文件的方法。我在过去尝试了一些简单的方法,对一个分数进行多次调用,完成一个校验和/斐波那契序列等,也用Amayeta SWF加密混淆SWF,但他们最终都被黑客入侵了。

感谢StackOverflow的响应,我现在从Adobe找到了更多的信息- http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps_12.html和https://github.com/mikechambers/as3corelib -我认为我可以使用加密。但我不确定这是否能让我绕过CheatEngine。

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

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


当前回答

你说的是所谓的“客户信任”问题。因为客户端(在这种现金中,运行在浏览器中的SWF)正在做它设计要做的事情。保存高分。

问题是,你想要确保“保存分数”请求来自你的flash电影,而不是任意的HTTP请求。一种可能的解决方案是在请求时(使用flasm)将服务器生成的令牌编码到SWF中,该令牌必须随请求一起保存高分。一旦服务器保存了该分数,令牌就过期了,不能再用于请求。

这样做的缺点是,用户每次加载flash电影只能提交一个高分——你不得不强迫他们刷新/重新加载SWF,然后他们才能再次播放新的分数。

其他回答

想要得到你想要的是不可能的。Flash应用程序的内部总是部分可访问的,特别是当你知道如何使用像CheatEngine这样的东西时,这意味着无论你的网站和浏览器<->服务器通信有多安全,它仍然会相对简单地克服。

你可能问错了问题。你似乎专注于人们通过游戏获得高分的方法,但阻止特定的方法也仅此而已。我没有TamperData的经验,所以我不能说。

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

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

这是有办法的。我在这里有一门课:http://divillysausages.com/blog/safenumber_and_safeint

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

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

我通常会在高分条目中加入游戏回合的“幽灵数据”。所以如果我在制作一款赛车游戏,我就会包含回放数据。你通常已经拥有关于重玩功能或幽灵赛车功能的重玩数据(游戏邦注:与你的上一场比赛进行比赛,或与排行榜上排名14的玩家的幽灵进行比赛)。

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

如果你的目标是将高分列表保持在网上,直到时间结束,而没有人需要查看它们,这不会给你带来太多好处。

I made kind of workaround... I had a gave where scores incremented ( you always get +1 score ). First, I started to count from random num (let's say 14 ) and when I display the scores, just showed the scores var minus 14. This was so if the crackers are looking for example for 20, they won't find it ( it will be 34 in the memory ). Second, since I know what the next point should be... I used adobe crypto library, to create the hash of what the next point should be. When I have to increment the scores, I check if the hash of the incremented scores is equal to the hash is should be. If the cracker have changed the points in the memory, the hashes are not equal. I perform some server-side verification and when I got different points from game and from the PHP, I know that cheating were involved. Here is snippet ot my code ( I'm using Adobe Crypto libraty MD5 class and random cryptography salt. callPhp() is my server side validation )

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游戏来说,这是一项艰巨的任务,但当涉及到奖品时,有些人就会变得贪婪。如果你需要任何帮助,给我写个便条。

欢呼,图标