php - ما هي أفضل طريقة لمنع الأشخاص من اختراق جدول أعلى الدرجات المبنية على PHP في لعبة Flash




9 Answers

هذه مشكلة كلاسيكية مع ألعاب الإنترنت والمسابقات. يعمل رمز الفلاش الخاص بك مع المستخدمين لتحديد النتيجة للعبة. لكن المستخدمين غير موثوقين ، ويتم تشغيل شفرة الفلاش على كمبيوتر المستخدم. أنت فقط لا يوجد شيء يمكنك القيام به لمنع مهاجم من تزوير درجات عالية:

  • إن الفلاش أسهل حتى من الهندسة العكسية مما قد تظنه ​​، حيث أن البايتات موثقة بشكل جيد وتصف لغة عالية المستوى (Actionscript) --- عندما تنشر لعبة فلاش ، أنت تنشر شفرة المصدر ، سواء كنت أعلم ذلك أم لا.

  • يتحكم المهاجمون في ذاكرة وقت تشغيل مترجم الفلاش ، بحيث يمكن لأي شخص يعرف كيفية استخدام مصحح برمجة قابل للتغيير أي متغير (بما في ذلك النتيجة الحالية) في أي وقت ، أو تغيير البرنامج نفسه.

أبسط هجوم ممكن ضد النظام الخاص بك هو تشغيل حركة مرور HTTP للعبة من خلال وكيل ، والقبض على حفظ درجة عالية ، واعادتها مع درجة أعلى.

يمكنك محاولة منع هذا الهجوم من خلال ربط كل درجة عالية بحفظ مثيل واحد من اللعبة ، على سبيل المثال عن طريق إرسال رمز مشفر إلى العميل عند بدء اللعبة ، والذي قد يبدو كالتالي:

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

(يمكنك أيضًا استخدام ملف تعريف ارتباط جلسة العمل بنفس التأثير).

رمز اللعبة أصداء هذا الرمز إلى الخادم مع حفظ درجة عالية. ولكن لا يزال بإمكان المهاجم بدء اللعبة مرة أخرى ، والحصول على رمز مميز ، ثم لصق ذلك الرمز على الفور إلى إعادة حفظ عالية المستوى.

لذلك ، بعد ذلك ، لا تطعم ملف تعريف الارتباط أو ملف تعريف ارتباط الجلسة فحسب ، بل أيضًا مفتاح جلسة تشفير عالية الدرجات. هذا سيكون مفتاح 128 بت AES ، مشفرة في حد ذاته مع مفتاح hardcoded في لعبة فلاش:

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 من الدرجة العالية (إذا قمت بتخطي هذه الخطوة ، فك التشفير سوف تنتج ببساطة عشوائية ، من المرجح عالية للغاية ، وعشرات عالية).

حتى الآن يقوم المهاجم بفك شفرة الفلاش الخاص بك وسرعان ما يجد رمز AES ، الذي يتلاشى مثل الإبهام ، على الرغم من أنه حتى لو لم يتم تعقبه في 15 دقيقة مع البحث عن الذاكرة والتتبع ("أعلم بلدي درجة لهذه اللعبة هو 666 ، لذلك دعونا نجد 666 في الذاكرة ، ثم التقاط أي عملية تلامس تلك القيمة --- يا نظرة ، رمز التشفير درجة عالية! "). باستخدام مفتاح الجلسة ، لا يحتاج المهاجم حتى إلى تشغيل شفرة الفلاش ؛ تلتقط رمزًا مميزًا للعبة ومفتاحًا للجلسة ، ويمكنها إرسال نقاط عالية بشكل عشوائي.

أنت الآن في النقطة التي يتخلى فيها معظم المطورين عن تقديم ما يلي: - إعطاء أو اتخاذ بضعة أشهر من العبث مع المهاجمين من خلال:

  • تخليط مفاتيح AES مع عمليات XOR

  • استبدال صفائف بايت الأساسية بوظائف حساب المفتاح

  • تشفير شفرات المفاتيح المزيفة وإعلانات درجة عالية في جميع أنحاء الثنائي.

هذا كله في الغالب مضيعة للوقت. وغني عن القول ، فإن SSL لن يساعدك أيضًا ؛ لا تستطيع طبقة المقابس الآمنة أن تحميك عندما تكون إحدى نقطتي SSL الشرّيتين.

فيما يلي بعض الأشياء التي يمكن أن تقلل من الاحتيال على درجة عالية:

  • يتطلب تسجيل الدخول لتشغيل اللعبة ، وجعل تسجيل الدخول ينتج ملف تعريف ارتباط جلسة عمل ، ولا تسمح بإطلاق عدة ألعاب معلقة في نفس الجلسة ، أو جلسات متعددة متزامنة لنفس المستخدم.

  • رفض درجات عالية من جلسات اللعبة التي تدوم أقل من أقصر الألعاب الحقيقية التي تم لعبها (من أجل نهج أكثر تعقيدًا ، جرّب "عزل" الدرجات العالية لجلسات الألعاب التي تدوم أقل من 2 انحرافات معيارية أقل من متوسط ​​مدة اللعبة). تأكد من أنك تتبع فترات اللعبة في سيرفريد.

  • رفض أو عزل نقاط عالية من تسجيلات الدخول التي لعبت اللعبة مرة أو مرتين فقط ، بحيث يجب على المهاجمين إنتاج "مسار ورقية" للعب لعبة تبحث عن كل تسجيل الدخول يخلق.

  • نتائج "Heartbeat" أثناء اللعب ، بحيث يرى خادمك نموًا في النتيجة على مدى عمر لعبة واحدة. رفض درجات عالية لا تتبع منحنيات درجة معقولة (على سبيل المثال ، القفز من 0 إلى 999999).

  • حالة لعبة "Snapshot" أثناء اللعب (على سبيل المثال ، كمية الذخيرة ، الموضع في المستوى ، إلخ) ، والتي يمكنك التوفيق فيما بينها مقابل النتائج المؤقتة المسجلة. ليس عليك حتى أن تكون لديك طريقة لاكتشاف الشذوذات في هذه البيانات لتبدأ بها ؛ عليك فقط جمعها ، ومن ثم يمكنك الرجوع إليها وتحليلها إذا بدت الأشياء مريبًا.

  • قم بتعطيل حساب أي مستخدم يخفق في أحد شيكاتك الأمنية (على سبيل المثال ، عن طريق إرسال درجة عالية مشفرة تفشل في التحقق من الصحة).

تذكر أنك لا ترد إلا الاحتيال على درجات عالية هنا. لا يوجد شيء يمكنك القيام به لمنع إذا. إذا كان هناك أموال على الخط في لعبتك ، فإن أحدهم سيهزم أي نظام تدخله. الهدف ليس وقف هذا الهجوم. انها لجعل الهجوم أكثر تكلفة من مجرد الحصول على جيد حقا في اللعبة وضربها.

أنا أتحدث عن لعبة حركة بلا حدود درجة عليا ولا توجد طريقة للتحقق من النتيجة على الخادم من خلال إعادة تشغيل التحركات وما إلى ذلك.

ما أريده حقاً هو أقوى تشفير ممكن في Flash / PHP ، وطريقة لمنع الأشخاص الذين يتصلون بصفحة PHP بخلاف ملف فلاش الخاص بي. لقد جربت بعض الطرق البسيطة في الماضي لإجراء مكالمات متعددة للحصول على درجة واحدة وإكمال تسلسل المجموع الاختباري / فيبوناتشي الخ ، وكذلك تشويش SWF مع تشفير Amayeta SWF ، ولكن تم اختراقها جميعًا في النهاية.

بفضل ردود ، وجدت الآن بعض المعلومات الإضافية من 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)




والطريقة السهلة للقيام بذلك هي توفير تجزئة مشفرة لقيمة أعلى الدرجات الخاصة بك جنبا إلى جنب مع درجة أنها النفس. على سبيل المثال ، عند نشر النتائج عبر HTTP GET: http://example.com/highscores.php?score=500&checksum=0a16df3dc0301a36a34f9065c3ff8095

عند حساب هذا المجموع الاختباري ، يجب استخدام سر مشترك ؛ هذا السر لا ينبغي أبدا أن ينتقل عبر الشبكة ، ولكن ينبغي أن يكون من الصعب ترميزها في كل من PHP backend وواجهة الفلاش. تم إنشاء المجموع الاختباري أعلاه عن طريق إرفاق سلسلة " سرية " إلى درجة " 500 " ، وتشغيله من خلال md5sum.

وبالرغم من أن هذا النظام سيمنع المستخدم من نشر نتائج عشوائية ، إلا أنه لا يمنع "هجوم إعادة التشغيل" ، حيث يقوم المستخدم بإعادة نشر مجموع النقاط والفرز المحسوب مسبقًا. في المثال أعلاه ، ينتج عن الدرجات 500 دائمًا نفس سلسلة التجزئة. يمكن تخفيف بعض هذه المخاطر من خلال دمج المزيد من المعلومات (مثل اسم المستخدم أو الطابع الزمني أو عنوان IP) في السلسلة التي سيتم تجزئتها. على الرغم من أن هذا لن يمنع إعادة تشغيل البيانات ، إلا أنه سيضمن أن مجموعة من البيانات صالحة فقط لمستخدم واحد في وقت واحد.

لمنع حدوث أي هجمات إعادة ، يجب إنشاء نوع من نظام الاستجابة للتحدي ، مثل ما يلي:

  1. تقوم لعبة فلاش ("العميل") بإجراء HTTP GET من http://example.com/highscores.php بدون أي معلمات. تُرجع هذه الصفحة قيمتين: قيمة ملح تم إنشاؤها عشوائيًا ، وتجزئة مشفرة لقيمة الملح هذه مقترنة بالسرية المشتركة. يجب تخزين قيمة الملح هذه في قاعدة بيانات محلية لطلبات البحث المعلقة ، ويجب أن يكون لها طابع زمني مرتبط بها بحيث يمكن "انتهاء صلاحيتها" بعد دقيقة واحدة.
  2. تجمع لعبة الفلاش بين قيمة الملح والسر المشترك وتحسب التجزئة للتحقق من أن هذا يتطابق مع القيمة التي يوفرها الخادم. هذه الخطوة ضرورية لمنع التلاعب بقيم الملح من قبل المستخدمين ، حيث تتحقق من أن قيمة الملح تم إنشاؤها بالفعل من قبل الخادم.
  3. تجمع لعبة الفلاش بين قيمة الملح والسر المشترك ، وقيمة الدرجة العالية ، وأية معلومات أخرى ذات صلة (كنية nickname ، ip ، timestamp) ، وتحسب التجزئة. ثم يرسل هذه المعلومات مرة أخرى إلى الخلفية PHP عبر HTTP GET أو POST ، جنبا إلى جنب مع قيمة الملح ، درجة عالية ، وغيرها من المعلومات.
  4. يجمع الخادم المعلومات المتلقاة بالطريقة نفسها الموجودة على العميل ، ويحسب التجزئة للتحقق من أن هذا يتطابق مع المعلومات التي يقدمها العميل. ثم يتحقق أيضًا من أن قيمة الملح لا تزال صالحة كما هو موضح في قائمة الاستعلام المعلقة. إذا كانت كلتا الحالتين صحيحتين ، فإنها تكتب الدرجة العالية لجدول النقاط المرتفعة وتعيد رسالة "نجاح" موقعة إلى العميل. كما يزيل قيمة الملح من قائمة الاستعلام المعلقة.

يرجى الأخذ في الاعتبار أن أمان أي من الأساليب المذكورة أعلاه قد تم اختراقه إذا كان الوصول إلى السر المشترك متاحًا للمستخدم

وكبديل ، يمكن تجنب بعض هذه الوصلات والعمليات من خلال إجبار العميل على الاتصال بالخادم عبر HTTPS ، والتأكد من أن العميل مكوّن مسبقًا ليثق فقط بالشهادات الموقعة من قِبل سلطة شهادات محددة والتي يمكنك الوصول إليها وحدها .




في الإجابة المقبولة ، تذكر tqbf أنه يمكنك فقط إجراء بحث عن الذاكرة لمتغير الدرجة ("My Score is 666 so look for the number 666 in memory").

هناك طريقة حول هذا. لدي فصل هنا: http://divillysausages.com/blog/safenumber_and_safeint

في الأساس ، لديك كائن لتخزين درجاتك. في المضبط يقوم بضرب القيمة التي تمررها مع رقم عشوائي (+ و -) ، وفي الثرت تقوم بقسمة القيمة المحفوظة بواسطة المضاعف العشوائي للحصول على النسخة الأصلية. الأمر بسيط ، ولكنه يساعد في إيقاف البحث عن الذاكرة.

أيضا ، تحقق من الفيديو من بعض اللاعبين وراء محرك PushButton الذين يتحدثون عن بعض الطرق المختلفة التي يمكنك بها مكافحة القرصنة: http://zaa.tv/2010/12/the-art-of-hacking-flash-games/ . كانوا هم الملهم وراء الفصل.




في تجربتي ، يتم التعامل مع هذا أفضل كمشكلة هندسة اجتماعية بدلاً من مشكلة برمجة. بدلا من التركيز على جعل من المستحيل للغش ، والتركيز على جعلها مملة عن طريق إزالة الحوافز للغش. على سبيل المثال ، إذا كان الحافز الرئيسي هو الدرجات العالية المرئية بشكل علني ، فإن مجرد تأخير التأخير عندما تظهر النتائج العالية يمكن أن يقلل بشكل كبير من الغش عن طريق إزالة حلقة التغذية الراجعة الإيجابية للغشاشين.




لقد تقدمت بنوع من الحل ... لقد حصلت على علامة حيث تزداد الدرجات (تحصل دائمًا على نتيجة +1). أولاً ، بدأت العد من الأرقام العشوائية (دعنا نقول 14) وعندما أقوم بعرض النتائج ، أظهرنا فقط الدرجات var ناقص 14. وكان ذلك إذا كانت البسكويت تبحث على سبيل المثال عن 20 ، فلن يعثر عليها ( سيكون 34 في الذاكرة). ثانيًا ، بما أنني أعرف ما يجب أن تكون عليه النقطة التالية ... استخدمت مكتبة crypto adobe ، لإنشاء تجزئة لما يجب أن تكون عليه النقطة التالية. عندما أحتاج إلى زيادة الدرجات ، أتحقق مما إذا كان تجزئة الدرجات المتزايدة يساوي التجزئة أم لا. إذا كان التكسير قد تغير النقاط في الذاكرة ، فإن التجزئة غير متساوية. أقوم ببعض التحقق من جانب الخادم وعندما حصلت على نقاط مختلفة من اللعبة ومن PHP ، أعلم أن هناك غشًا. هنا مقتطف ot رمز بلدي (أنا باستخدام الفئة 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");
            }
        }

باستخدام هذه التقنية + wffication 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
}

ثم أقوم بإرسال المتغير مع غيرها من الفاسات المزيفة وفقدنا الطريق فقط ... إنه الكثير من العمل لمجرد لعبة فلاش صغيرة ، ولكن حيث يتم إشراك الجوائز بعض الناس فقط الحصول على الجشع. إذا كنت بحاجة إلى أي مساعدة ، اكتب لي م.

ابتهاج ، إيكو




لا توجد طريقة لجعله غير قابل للإصلاح تمامًا ، حيث أنه من السهل فك رموز ملفات SWF ، ومن ثم يمكن لمتطفلي برامج الكمبيوتر ذوي المهارات من خلال التتبع تتبع الشفرة الخاصة بك والتعرف على كيفية تجاوز أي نظام مشفر قد تستخدمه.

إذا كنت ترغب ببساطة في منع الأطفال من الغش عبر استخدام أدوات بسيطة مثل TamperData ، فيمكنك إنشاء مفتاح تشفير تمرره إلى SWF عند بدء التشغيل. ثم استخدم شيئًا مثل http://code.google.com/p/as3crypto/ لتشفير درجة عالية قبل تمريرها إلى شفرة PHP. ثم فك تشفيرها في نهاية الخادم قبل تخزينها في قاعدة البيانات.




أنا عادة ما تشمل "بيانات الأشباح" من جلسة اللعبة مع دخول أعلى الدرجات. لذلك إذا صنعت لعبة سباق ، فأنا أضمِّن بيانات إعادة التشغيل. غالبًا ما يكون لديك بيانات إعادة التشغيل بالفعل من أجل وظيفة إعادة التشغيل أو وظيفة سباق الشبح (اللعب ضد السباق الأخير ، أو اللعب ضد شبح المتأنق رقم 14 على المتصدرين).

يعتبر التحقق من هذه الأعمال عملاً يدويًا للغاية ، ولكن إذا كان الهدف هو التحقق مما إذا كانت أهم 10 مشاركات في المسابقة شرعية ، فيمكن أن يكون هذا إضافة مفيدة لترسانة الإجراءات الأمنية التي أشار إليها آخرون بالفعل.

إذا كان الهدف هو إبقاء قائمة أفضل الحاصدات على الإنترنت حتى نهاية الوقت دون أن يضطر أي شخص إلى النظر إليها ، فإن هذا لن يجلب لك الكثير.




أعتقد أن أبسط طريقة هي إجراء مكالمات إلى وظيفة مثل RegisterScore (النتيجة) في كل مرة تسجل فيها اللعبة نقاطًا ليتم إضافتها ثم ترميزها ، وتعبئتها وإرسالها إلى برنامج نصي php كسلسلة. سيعرف برنامج php النصي كيفية فك ترميزه بشكل صحيح. هذا من شأنه أن يوقف أي مكالمات مباشرة إلى البرنامج النصي php حيث أن أي محاولة لفرض النتيجة سيؤدي إلى خطأ في إلغاء الضغط.




ليس من الممكن حقًا تحقيق ما تريد. يتم دائمًا الوصول إلى CheatEngine الداخلية من تطبيق Flash جزئيًا ، خاصة عندما تعرف كيفية استخدام أشياء مثل CheatEngine ، وهذا يعني بغض النظر عن مدى أمان موقع الويب الخاص بك والمتصفح <-> اتصالات الخادم ، فإنه لا يزال من السهل التغلب عليه.




Related

php actionscript-3 security actionscript actionscript-2