फ्लैश गेम की PHP- आधारित हाईस्कोर तालिका को हैक करने वाले लोगों को रोकने का सबसे अच्छा तरीका क्या है




actionscript-3 security (12)

मैं एक एक्शन गेम के बारे में बात कर रहा हूं जिसमें कोई ऊपरी स्कोर सीमा नहीं है और चाल चलाना आदि द्वारा सर्वर पर स्कोर को सत्यापित करने का कोई तरीका नहीं है।

मुझे वास्तव में फ्लैश / PHP में सबसे मजबूत एन्क्रिप्शन संभव है, और मेरी फ्लैश फ़ाइल के माध्यम से PHP पृष्ठ को कॉल करने वाले लोगों को रोकने का एक तरीका है। मैंने एक ही स्कोर के लिए कई कॉल करने और चेकसम / फाइबोनैकी अनुक्रम इत्यादि को पूरा करने के अतीत में कुछ सरल तरीकों की कोशिश की है, और अमायेट एसडब्ल्यूएफ एन्क्रिप्टेड के साथ एसडब्ल्यूएफ को भी खराब कर दिया है, लेकिन अंत में वे सभी हैक किए गए थे।

StackOverflow प्रतिक्रियाओं के लिए धन्यवाद अब मुझे एडोब - http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps_12.html और https://github.com/mikechambers/as3corelib से कुछ और जानकारी मिली है - जो मुझे लगता है कि मैं एन्क्रिप्शन के लिए उपयोग कर सकते हैं। यकीन नहीं है कि यह मुझे CheatEngine के आसपास मिल जाएगा हालांकि।

अगर वे अलग हैं तो मुझे एएस 2 और एएस 3 दोनों के लिए सबसे अच्छे समाधान जानने की जरूरत है।

मुख्य समस्याएं TamperData और LiveHTTP शीर्षलेख जैसी चीजें प्रतीत होती हैं, लेकिन मुझे लगता है कि अधिक उन्नत हैकिंग टूल भी हैं - जैसे CheatEngine (धन्यवाद मार्क वेबस्टर)


आप "क्लाइंट ट्रस्ट" समस्या कहलाते हैं इसके बारे में बात कर रहे हैं। चूंकि क्लाइंट (इस नकदी में, एक ब्राउज़र में चल रहा एक एसडब्ल्यूएफ) ऐसा कुछ कर रहा है जो इसे करने के लिए डिज़ाइन किया गया है। एक उच्च स्कोर बचाओ।

समस्या यह है कि आप यह सुनिश्चित करना चाहते हैं कि "फ्लैश स्कोर" अनुरोध आपकी फ्लैश मूवी से आ रहे हैं, और कुछ मनमाने ढंग से HTTP अनुरोध नहीं। इसके लिए एक संभावित समाधान सर्वर द्वारा जेनरेट किए गए टोकन को अनुरोध के समय एसडब्ल्यूएफ में flasm करना है ( flasm का उपयोग flasm ) जो उच्च स्कोर को बचाने के अनुरोध के साथ होना चाहिए। एक बार जब सर्वर उस स्कोर को सहेज लेता है, तो टोकन समाप्त हो जाता है और अब अनुरोधों के लिए उपयोग नहीं किया जा सकता है।

इसका नकारात्मक पक्ष यह है कि उपयोगकर्ता केवल फ्लैश मूवी के प्रति लोड के एक उच्च स्कोर जमा करने में सक्षम होगा - आपको उन्हें नए स्कोर के लिए फिर से खेलने से पहले एसडब्ल्यूएफ को रीफ्रेश / पुनः लोड करने के लिए मजबूर करना होगा।


आप गलत सवाल पूछ रहे हैं। आप उच्च स्कोर सूची में अपना रास्ता खेलने के तरीकों पर ध्यान केंद्रित करते हैं, लेकिन विशिष्ट तरीकों को अवरुद्ध करना अभी तक चला जाता है। मुझे TamperData के साथ कोई अनुभव नहीं है, इसलिए मैं उससे बात नहीं कर सकता।

आपको जो प्रश्न पूछना चाहिए वह यह है: "मैं कैसे सत्यापित कर सकता हूं कि सबमिट किए गए स्कोर वैध और प्रामाणिक हैं?" ऐसा करने का विशिष्ट तरीका गेम-निर्भर है। बहुत ही सरल पहेली गेम के लिए, आप विशिष्ट प्रारंभिक स्थिति और अंतराल के परिणामस्वरूप चाल के अनुक्रम के साथ स्कोर भेज सकते हैं, और फिर उसी चाल का उपयोग कर सर्वर पक्ष पर गेम को फिर से चला सकते हैं। पुष्टि करें कि कहा गया स्कोर गणना स्कोर के समान है और यदि वे मेल खाते हैं तो केवल स्कोर स्वीकार करें।


इसे पूरी तरह से अनावश्यक बनाने का कोई तरीका नहीं है, क्योंकि एसडब्ल्यूएफ को कम करना आसान है, और एक कुशल डेवलपर हैकर तब आपके कोड के माध्यम से पता लगा सकता है और आपके द्वारा नियोजित किसी भी एन्क्रिप्टेड सिस्टम को बाईपास करने का तरीका बता सकता है।

यदि आप बस टम्परडाटा जैसे सरल टूल के उपयोग के माध्यम से बच्चों को धोखा देना चाहते हैं, तो आप स्टार्टअप पर एसडब्ल्यूएफ को पास करने वाली एन्क्रिप्शन कुंजी उत्पन्न कर सकते हैं। फिर PHP कोड पर वापस जाने से पहले उच्च स्कोर एन्क्रिप्ट करने के लिए http://code.google.com/p/as3crypto/ जैसे कुछ का उपयोग करें। फिर डेटाबेस में इसे संग्रहीत करने से पहले सर्वर अंत में इसे डिक्रिप्ट करें।


ऐसा करने का एक आसान तरीका यह है कि अपने उच्च स्कोर के मूल्य के साथ एक क्रिप्टोग्राफिक हैश प्रदान करें। उदाहरण के लिए, HTTP GET के माध्यम से परिणाम पोस्ट करते समय: http://example.com/highscores.php?score=500&checksum=0a16df3dc0301a36a34f9065c3ff8095

इस चेकसम की गणना करते समय, एक साझा रहस्य का उपयोग किया जाना चाहिए; इस रहस्य को नेटवर्क पर कभी भी प्रसारित नहीं किया जाना चाहिए, लेकिन PHP बैकएंड और फ्लैश फ्रंटेंड दोनों में हार्ड कोड किया जाना चाहिए। उपरोक्त चेकसम " 500 " स्कोर के लिए " गुप्त " स्ट्रिंग को प्रीपेड करके और md5sum के माध्यम से इसे चलाकर बनाया गया था।

यद्यपि यह सिस्टम किसी उपयोगकर्ता को मनमानी स्कोर पोस्ट करने से रोक देगा, लेकिन यह "रीप्ले अटैक" को नहीं रोकता है, जहां कोई उपयोगकर्ता पहले गणना किए गए स्कोर और हैश संयोजन को दोबारा पोस्ट करता है। उपर्युक्त उदाहरण में, 500 का स्कोर हमेशा एक ही हैश स्ट्रिंग का उत्पादन करेगा। इस जोखिम में से कुछ को स्ट्रिंग में अधिक जानकारी (जैसे उपयोगकर्ता नाम, टाइमस्टैंप, या आईपी पता) को शामिल करके कम किया जा सकता है। हालांकि यह डेटा के पुनरावृत्ति को नहीं रोकेगा, यह बीमा करेगा कि डेटा का एक सेट केवल एक ही उपयोगकर्ता के लिए एक ही समय में मान्य है।

किसी भी रीप्ले हमले होने से रोकने के लिए, कुछ प्रकार की चुनौती-प्रतिक्रिया प्रणाली को बनाना होगा, जैसे कि निम्न:

  1. फ्लैश गेम ("क्लाइंट") बिना किसी पैरामीटर के http://example.com/highscores.php का HTTP GET निष्पादित करता है। यह पृष्ठ दो मान देता है: एक यादृच्छिक रूप से जेनरेट किया गया नमक मान, और साझा नमक के साथ संयुक्त नमक मूल्य का क्रिप्टोग्राफ़िक हैश। यह नमक मान लंबित प्रश्नों के स्थानीय डेटाबेस में संग्रहीत किया जाना चाहिए, और इसमें एक टाइमस्टैम्प होना चाहिए ताकि वह शायद एक मिनट के बाद "समाप्त हो सके"।
  2. फ़्लैश खेल साझा रहस्य के साथ नमक मूल्य को जोड़ता है और यह सत्यापित करने के लिए हैश की गणना करता है कि यह सर्वर द्वारा प्रदान किए गए किसी से मेल खाता है। उपयोगकर्ताओं द्वारा नमक मूल्यों के साथ छेड़छाड़ को रोकने के लिए यह कदम आवश्यक है, क्योंकि यह सत्यापित करता है कि नमक मूल्य वास्तव में सर्वर द्वारा उत्पन्न किया गया था।
  3. फ़्लैश खेल साझा रहस्य, उच्च स्कोर मूल्य, और किसी भी अन्य प्रासंगिक जानकारी (उपनाम, आईपी, टाइमस्टैम्प) के साथ नमक मूल्य को जोड़ता है, और एक हैश की गणना करता है। इसके बाद यह नमक मूल्य, उच्च स्कोर और अन्य जानकारी के साथ HTTP GET या POST के माध्यम से PHP बैकएंड पर इस जानकारी को वापस भेजता है।
  4. सर्वर क्लाइंट के समान तरीके से प्राप्त जानकारी को जोड़ता है, और यह सत्यापित करने के लिए हैश की गणना करता है कि यह क्लाइंट द्वारा प्रदान किए गए किसी से मेल खाता है। यह तब भी सत्यापित करता है कि लंबित क्वेरी सूची में सूचीबद्ध नमक मान अभी भी मान्य है। यदि ये दोनों स्थितियां सत्य हैं, तो यह उच्च स्कोर तालिका में उच्च स्कोर लिखती है और ग्राहक को हस्ताक्षरित "सफलता" संदेश लौटाती है। यह लंबित क्वेरी सूची से नमक मूल्य भी हटा देता है।

कृपया ध्यान रखें कि उपरोक्त किसी भी तकनीक की सुरक्षा से समझौता किया गया है यदि साझा रहस्य उपयोगकर्ता के लिए कभी भी सुलभ है

एक विकल्प के रूप में, क्लाइंट को एचटीटीपीएस पर सर्वर के साथ संवाद करने के लिए मजबूर कर दिया गया है, और यह सुनिश्चित करना कि क्लाइंट को केवल एक विशिष्ट प्रमाणपत्र प्राधिकरण द्वारा हस्ताक्षरित प्रमाणपत्रों पर भरोसा करने के लिए पूर्वसंरचित किया गया है, जिसे आप अकेले पहुंच सकते हैं ।


जब भी आपका हाईस्कॉर सिस्टम इस तथ्य पर आधारित होता है कि फ्लैश एप्लिकेशन नेटवर्क के माध्यम से अनएन्क्रिप्टेड / हस्ताक्षरित हाईस्कॉर डेटा भेजता है, जिसे अवरुद्ध और छेड़छाड़ / दोहराया जा सकता है। उत्तर उस से मिलता है: एन्क्रिप्ट (decently!) या क्रिप्टोग्राफिक हाईस्कॉर डेटा पर हस्ताक्षर करें। यह, कम से कम, लोगों को आपके हाईस्कॉर सिस्टम को क्रैक करना कठिन बनाता है क्योंकि उन्हें आपकी एसडब्ल्यूएफ फ़ाइल से गुप्त कुंजी निकालने की आवश्यकता होगी। बहुत से लोग शायद वहां छोड़ देंगे। दूसरी तरफ, यह सब कुछ लेता है और इसे कहीं भी पोस्ट करने के लिए एकमात्र व्यक्ति होता है।

वास्तविक समाधानों में फ्लैश एप्लिकेशन और हाईस्कॉर डेटाबेस के बीच अधिक संचार शामिल है ताकि बाद वाले यह सत्यापित कर सकें कि दिया गया स्कोर कुछ हद तक यथार्थवादी है। यह संभवतः जटिल है कि आपको किस तरह का गेम मिला है।


जिस तरह से एक नया लोकप्रिय आर्केड मोड यह करता है कि यह फ़्लैश से php तक डेटा भेजता है, वापस फ्लैश (या इसे पुनः लोड करता है), फिर वापस php पर भेजता है। यह आपको डेटा की तुलना करने के साथ-साथ पोस्ट डेटा / डिक्रिप्शन हैक्स और इसी तरह की तुलना करने के लिए कुछ भी करने की अनुमति देता है। एक तरीका यह है कि यह php से 2 यादृच्छिक मानों को फ्लैश में निर्दिष्ट करता है (जिसे आप रीयलटाइम फ्लैश डेटा हथियार चलाते हुए भी पकड़ नहीं सकते हैं या देख सकते हैं), यादृच्छिक मानों के साथ स्कोर जोड़ने के लिए गणितीय सूत्र का उपयोग करके इसे जांचकर यह देखने के लिए एक ही फॉर्मूला है कि यह देखने के लिए कि स्कोर अंततः PHP पर अंत में जाता है या नहीं। ये यादृच्छिक मान कभी भी दिखाई नहीं दे रहे हैं और साथ ही साथ लेन-देन के समय भी होते हैं और यदि यह कुछ सेकंड से अधिक है तो यह इसे धोखाधड़ी के रूप में भी झुकाता है क्योंकि ऐसा लगता है कि आपने यादृच्छिक मानों को चलाने या चलाने का प्रयास करने के लिए प्रेषण को रोक दिया है स्कोर मूल्य के साथ तुलना करने के लिए संभावित यादृच्छिक मानों को वापस करने के लिए कुछ प्रकार के सिफर के माध्यम से संख्याएं।

यदि आप मुझसे पूछते हैं तो यह एक बहुत अच्छा समाधान लगता है, क्या कोई इस विधि का उपयोग करने के साथ कोई समस्या देखता है? या इसके आसपास के संभावित तरीके?


मुझे पसंद है कि टीपीक्यूएफ ने क्या कहा, लेकिन धोखाधड़ी की खोज के दौरान खाते को अक्षम करने के बजाय, एक हनीपॉट को लागू करें ताकि जब भी वे लॉग इन हों, वे अपने हैक किए गए स्कोर देखें और कभी संदेह न करें कि उन्हें ट्रोल के रूप में चिह्नित किया गया है। "Phpbb एमओडी ट्रॉल" के लिए Google और आपको एक सरल दृष्टिकोण दिखाई देगा।


मुझे लगता है कि जब भी गेम स्कोर को स्कोर करने के लिए पंजीकरण करता है और फिर इसे एन्कोड करता है, उसे पैकेज करता है और इसे स्ट्रिंग के रूप में एक php स्क्रिप्ट पर भेजता है तो रजिस्टरस्टकोर (स्कोर) जैसे किसी फ़ंक्शन पर कॉल करना सबसे आसान तरीका होगा। PHP स्क्रिप्ट को यह पता चलेगा कि इसे ठीक से कैसे डीकोड किया जाए। यह किसी भी कॉल को सीधे PHP स्क्रिप्ट पर रोक देगा क्योंकि किसी भी स्कोर को मजबूर करने का प्रयास करने से कोई डिकंप्रेशन त्रुटि हो जाएगी।


मैं आमतौर पर हाईस्कॉर एंट्री के साथ गेम सत्र का "भूत डेटा" शामिल करता हूं। तो अगर मैं रेसिंग गेम बना रहा हूं, तो मैं रीप्ले डेटा शामिल करता हूं। आपके पास रीप्ले कार्यक्षमता या भूत रेसिंग कार्यक्षमता के लिए पहले से ही रीप्ले डेटा होता है (आपकी पिछली दौड़ के खिलाफ खेलना, या लीडरबोर्ड पर दोस्त # 14 के भूत के खिलाफ खेलना)।

इन्हें जांचना बहुत मैन्युअल श्रम है, लेकिन यदि लक्ष्य यह सत्यापित करना है कि प्रतियोगिता में शीर्ष 10 प्रविष्टियां कानूनी हैं, तो यह सुरक्षा उपायों के शस्त्रागार के लिए एक उपयोगी अतिरिक्त हो सकता है जो दूसरों ने पहले ही बताया है।

यदि लक्ष्य हाईस्कॉर्क्स सूची ऑनलाइन रखने के लिए समय के अंत तक बिना किसी को देखे, तो यह आपको ज्यादा नहीं लाएगा।


मैंने कामकाज किया ... मैंने एक दिया था जहां स्कोर बढ़े थे (आपको हमेशा +1 स्कोर मिलता है)। सबसे पहले, मैंने यादृच्छिक संख्या से गिनना शुरू कर दिया (चलो 14 कहें) और जब मैं स्कोर प्रदर्शित करता हूं, तो सिर्फ स्कोर कम से कम 14 दिखाता है। ऐसा इसलिए था अगर क्रैकर्स 20 के लिए उदाहरण की तलाश में हैं, तो उन्हें यह नहीं मिलेगा (यह स्मृति में 34 होगा)। दूसरा, क्योंकि मुझे पता है कि अगला बिंदु क्या होना चाहिए ... मैंने एडोब क्रिप्टो लाइब्रेरी का उपयोग किया, ताकि अगले बिंदु के हश को बनाने के लिए । जब मुझे स्कोर में वृद्धि करना है, तो मैं जांचता हूं कि बढ़ी हुई स्कोर का हैश हैश के बराबर है या नहीं। अगर क्रैकर ने स्मृति में अंक बदल दिए हैं, तो हैंश बराबर नहीं हैं। मैं कुछ सर्वर-साइड सत्यापन करता हूं और जब मुझे गेम से और PHP से अलग-अलग अंक मिलते हैं, तो मुझे पता है कि धोखाधड़ी शामिल थी। यहां मेरा कोड स्निपेट है (मैं एडोब क्रिप्टो लाइब्रेटी एमडी 5 क्लास और यादृच्छिक क्रिप्टोग्राफी नमक का उपयोग कर रहा हूं। 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");
            }
        }

इस तकनीक का उपयोग + एसडब्ल्यूएफ 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
}

फिर मैं वैरिएबल को अन्य नकली-वर्रों के साथ भेजता हूं और यह सिर्फ रास्ते में खो जाता है ... यह केवल छोटे फ़्लैश खेल के लिए बहुत काम है, लेकिन जहां पुरस्कार शामिल होते हैं तो कुछ लोग लालची हो जाते हैं। अगर आपको किसी मदद की ज़रूरत है, तो मुझे एक पीएम लिखें।

चीयर्स, इको


स्वीकार्य उत्तर में tqbf का उल्लेख है कि आप स्कोर चर के लिए केवल एक स्मृति खोज कर सकते हैं ("मेरा स्कोर 666 है इसलिए मैं स्मृति में 666 की संख्या देखता हूं")।

इसके चारों ओर एक रास्ता है। मेरे पास यहां एक कक्षा है: http://divillysausages.com/blog/safenumber_and_safeint

असल में, आपके पास अपना स्कोर स्टोर करने का ऑब्जेक्ट है। सेटर में यह उस मान को गुणा करता है जिसे आप इसे यादृच्छिक संख्या (+ और -) से पास करते हैं, और गेटटर में आप सहेजे गए मान को मूल बैक प्राप्त करने के लिए यादृच्छिक गुणक द्वारा विभाजित करते हैं। यह आसान है, लेकिन स्मृति खोज को रोकने में मदद करता है।

इसके अलावा, पुशबटन इंजन के पीछे कुछ लोगों से वीडियो देखें जो हैकिंग का मुकाबला करने के कुछ अलग-अलग तरीकों के बारे में बात करते हैं: http://zaa.tv/2010/12/the-art-of-hacking-flash-games/ । वे कक्षा के पीछे प्रेरणा थीं।


AMFPHP माध्यम से बैकएंड के साथ संवाद करना एक अच्छा विचार हो सकता है। इसे कम से कम आलसी लोगों को ब्राउज़र कंसोल के माध्यम से परिणामों को धक्का देने की कोशिश से हतोत्साहित करना चाहिए।





actionscript-2