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

我真正需要的是在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,一个熟练的开发黑客可以跟踪您的代码,并找出如何绕过您可能使用的任何加密系统。

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

其他回答

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

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

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

可能会定期将数据发送回服务器并进行一些验证。不要把注意力集中在客户端代码上,即使您的应用程序就在客户端代码上。

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

欢呼,图标

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

但你也可以加入游戏长度(同样是加密的)和点击次数等变量。

所有这类事情都可以逆向工程,所以可以考虑扔进一堆垃圾数据来迷惑人们。

编辑:可能也值得加入一些PHP会话。当玩家点击“开始游戏”时便开始游戏,并记录时间。当他们提交分数时,你可以检查他们是否有一个开放的游戏,他们没有过早或过大地提交分数。

也许有必要计算出一个标量,比如每秒钟/分钟游戏的最大分数。

这两件事都不是不可避免的,但这将有助于在Flash之外的地方设置一些逻辑,让人们可以看到它。