it-swarm-ru.tech

Каков наилучший способ остановить людей, взламывающих таблицу рекордов на основе PHP во Flash-игре?

Я говорю об экшн-игре без верхнего предела очков и без возможности проверить счет на сервере путем воспроизведения ходов и т.д.

Что мне действительно нужно, так это самое надежное шифрование, возможное во Flash/PHP, и способ запретить людям вызывать страницу PHP иначе, чем через мой файл Flash. В прошлом я пробовал несколько простых методов: сделать несколько вызовов для одного счета, завершить последовательность контрольных сумм/фибоначчи и т.д., А также скрыть SWF с помощью Amayeta SWF Encrypt, но все они в конечном итоге были взломаны.

Благодаря ответам 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 (спасибо Марку Вебстеру)

212
Iain

Это классическая проблема с интернет-играми и конкурсами. Ваш Flash-код работает с пользователями, чтобы определить счет для игры. Но пользователям не доверяют, и код Flash выполняется на компьютере пользователя. Ты SOL. Вы ничего не можете сделать, чтобы не дать злоумышленнику подделать высокие баллы:

  • Обратиться к 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; она берет токен запуска игры и сеансовый ключ и может отправить произвольный высокий балл.

Теперь вы находитесь в точке, когда большинство разработчиков просто сдаются - дают или берут пару месяцев возиться с злоумышленниками:

  • Скремблирование клавиш AES с помощью операций XOR

  • Замена байтовых массивов клавиш функциями, вычисляющими ключ

  • Рассеяние фальшивых ключей шифрования и высокий рейтинг сообщений по всему бинарному.

Это все в основном пустая трата времени. Разумеется, SSL вам тоже не поможет; SSL не может защитить вас, когда одна из двух конечных точек SSL является злой.

Вот некоторые вещи, которые на самом деле могут уменьшить мошенничество с высокими баллами:

  • Для входа в игру требуется логин, чтобы логин генерировал сессионный куки-файл, и чтобы не допускались многократные запуски игры в одном сеансе или несколько одновременных сеансов для одного и того же пользователя.

  • Отклоните высокие оценки от игровых сессий, которые длятся меньше, чем самые короткие реальные игры, в которые когда-либо играли (для более сложного подхода, попробуйте "изолировать" высокие оценки для игровых сессий, которые длятся менее чем на 2 стандартных отклонения ниже средней продолжительности игры). Убедитесь, что вы отслеживаете продолжительность игры на сервере.

  • Отклонять или помещать в карантин высокие результаты по логинам, которые играли в игру только один или два раза, так что злоумышленники должны составлять "бумажный след" разумного вида игры для каждого создаваемого им входа.

  • "Сердцебиение" набирает очки во время игры, поэтому ваш сервер видит рост очков за время одного игрового процесса. Отклонить высокие баллы, которые не соответствуют разумным кривым баллов (например, прыжки от 0 до 999999).

  • "Снимок" игрового состояния во время игры (например, количество боеприпасов, положение на уровне и т.д.), Которые вы можете позже согласовать с записанными промежуточными результатами. Вам даже не нужно иметь возможность обнаруживать аномалии в этих данных, чтобы начать с них; вам просто нужно собрать его, а затем вы можете вернуться и проанализировать его, если все выглядит подозрительно.

  • Отключите учетную запись любого пользователя, который не прошел ни одну из ваших проверок безопасности (например, отправив зашифрованный высокий балл, который не прошел проверку).

Помните, однако, что вы только сдерживаете мошенничество с высокими показателями здесь. Там ничего вы можете сделать, чтобы предотвратить, если. Если в вашей игре есть деньги на линии, кто-то собирается победить любую систему, с которой вы столкнетесь. Цель не в том, чтобы остановить эту атаку; это сделать атаку более дорогой, чем просто получить действительно хорошую игру и обыграть ее.

414
tqbf

Вы можете задавать неправильный вопрос. Вы, кажется, сосредоточены на методах, которые люди используют, чтобы подняться наверх в списке рекордов, но блокирование определенных методов идет только так далеко. У меня нет опыта работы с TamperData, поэтому я не могу говорить об этом.

Вопрос, который вы должны задать: "Как я могу проверить, что представленные результаты действительны и достоверны?" Конкретный способ сделать это зависит от игры. В очень простых играх-головоломках вы можете отправить счет вместе с определенным начальным состоянием и последовательностью ходов, которые привели к конечному состоянию, а затем повторно запустить игру на стороне сервера, используя те же самые ходы. Убедитесь, что заявленная оценка совпадает с расчетной, и принимайте ее, только если они совпадают.

25
Stephen Deken

Самый простой способ сделать это - предоставить криптографический хеш-код вашей высокой оценки вместе с собственным баллом. Например, при публикации результатов через HTTP GET: http://example.com/highscores.php?score=500&checksum=0a16df3dc0301a36a34f9065c3ff8095

При расчете этой контрольной суммы следует использовать общий секрет; этот секрет никогда не должен передаваться по сети, но должен быть жестко закодирован как внутри PHP бэкэнда, так и во внешнем интерфейсе флэш-памяти. Контрольная сумма выше была создана путем добавления строки " secret " к счету " 500 "и запускаю его через md5sum.

Хотя эта система не позволяет пользователю публиковать произвольные оценки, она не предотвращает "атаку с повторным воспроизведением", когда пользователь повторно публикует ранее рассчитанную комбинацию оценок и хэшей. В приведенном выше примере оценка 500 всегда будет приводить к одной и той же хэш-строке. Часть этого риска можно уменьшить, включив дополнительную информацию (например, имя пользователя, метку времени или IP-адрес) в строку, которую необходимо хэшировать. Хотя это не помешает воспроизведению данных, оно гарантирует, что набор данных действителен только для одного пользователя в одно время.

Чтобы предотвратить любые атаки повторного воспроизведения, необходимо создать систему типа "вызов-ответ", такую ​​как следующее:

  1. Флэш-игра ("клиент") выполняет HTTP GET http://example.com/highscores.php без параметров. Эта страница возвращает два значения: случайно сгенерированное значение соли и криптографический хэш этого значения соли в сочетании с общим секретом. Это солт-значение должно храниться в локальной базе данных ожидающих запросов, и с ним должна быть связана временная метка, чтобы он мог "истечь", возможно, через одну минуту.
  2. Флэш-игра объединяет солт-значение с общим секретом и вычисляет хеш, чтобы убедиться, что он соответствует тому, который предоставлен сервером. Этот шаг необходим для предотвращения подмены значений соли пользователями, поскольку он проверяет, что значение соли фактически было сгенерировано сервером.
  3. Флэш-игра объединяет солт-значение с общим секретом, значением старшего балла и любой другой релевантной информацией (псевдоним, ip, метка времени) и вычисляет хэш. Затем он отправляет эту информацию обратно в бэкэнд PHP через HTTP GET или POST, а также солт-значение, высокий балл и другую информацию.
  4. Сервер объединяет информацию, полученную таким же образом, как и на клиенте, и вычисляет хеш, чтобы убедиться, что он совпадает с хешем, предоставленным клиентом. Затем он также проверяет, что значение соли все еще является действительным, как указано в списке ожидающих запросов. Если оба эти условия выполняются, он записывает рекорд в таблицу рекордов и возвращает клиенту подписанное сообщение об успехе. Он также удаляет значение соли из списка ожидающих запросов.

Пожалуйста, имейте в виду, что безопасность любого из вышеперечисленных методов ставится под угрозу, если общий секрет когда-либо доступен пользователю

В качестве альтернативы, некоторых из этих возвратов можно было бы избежать, если заставить клиента взаимодействовать с сервером по протоколу HTTPS и убедиться, что клиент предварительно настроен на доверие только сертификатам, подписанным определенным центром сертификации, к которому у вас есть доступ. ,.

18
stormlash

Мне нравится то, что сказал tpqf, но вместо того, чтобы отключать учетную запись при обнаружении мошенничества, реализуйте honeypot, чтобы при входе в систему они видели свои взломанные результаты и никогда не подозревали, что их пометили как тролля. Google для "phpBB MOD Troll", и вы увидите оригинальный подход.

11
DGM

Я сделал своего рода обходной путь ... У меня был дан, где увеличены оценки (вы всегда получаете +1 балл). Во-первых, я начал считать со случайного числа (скажем, 14), и когда я отображал баллы, просто показывал баллы var минус 14. Это было так, если взломщики ищут, например, 20, они не найдут его (это будет 34 в памяти). Во-вторых, поскольку я знаю, какой должна быть следующая точка ... Я использовал криптографическую библиотеку Adobe, чтобы создать хэш следующей точки должен быть. Когда мне нужно увеличить баллы, я проверяю, должен ли хеш инкрементных баллов быть равен хешу. Если взломщик изменил точки в памяти, хэши не равны. Я провожу некоторые проверки на стороне сервера, и когда я получаю разные очки от игры и от PHP, я знаю, что это связано с мошенничеством. Вот фрагмент моего кода (я использую класс 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");
            }
        }

Используя эту технику + обфускация 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
}

Затем я отправляю переменную среди других фальшивых переменных, и она просто теряется в пути ... Это большая работа для небольшой флэш-игры, но там, где участвуют призы, некоторые люди просто становятся жадными. Если вам нужна помощь, напишите мне в личку.

Ура, Ико

4

В принятом ответе tqbf упоминает, что вы можете просто выполнить поиск в памяти для переменной счета ("Мой счет - 666, поэтому я ищу число 666 в памяти").

Есть способ обойти это. У меня есть класс здесь: http://divillysausages.com/blog/safenumber_and_safeint

По сути, у вас есть объект для хранения вашего счета. В установщике он умножает передаваемое им значение на случайное число (+ и -), а в получателе вы делите сохраненное значение на случайный мультипликатор, чтобы вернуть оригинал. Это просто, но помогает остановить поиск в памяти.

Также посмотрите видео с парнями из движка PushButton, рассказывающими о различных способах борьбы со взломом: http://zaa.tv/2010/12/the-art-of- взлом-флеш-игры / . Они были вдохновением для класса.

4
divillysausages

Вы не можете доверять никаким данным, которые возвращает клиент. Проверка должна быть выполнена на стороне сервера. Я не разработчик игр, но я делаю программное обеспечение для бизнеса. В обоих случаях могут быть задействованы деньги, и люди будут ломать методы запутывания на стороне клиента.

Может быть, периодически отправлять данные обратно на сервер и проводить некоторую проверку. Не сосредотачивайтесь на клиентском коде, даже если это то место, где живет ваше приложение.

3
zeller

Шифрование с использованием известного (частного) обратимого ключа было бы самым простым методом. Я не все в AS, поэтому я не уверен, какие существуют поставщики шифрования.

Но вы можете включить такие переменные, как продолжительность игры (снова зашифрованные) и количество кликов.

Все подобные вещи могут быть перепроектированы, поэтому подумайте о том, чтобы добавить кучу ненужных данных, чтобы сбить людей с толку.

Правка: Возможно, стоит попробовать и в некоторых сессиях PHP. Начните сеанс, когда они нажмут начать игру и (как говорится в комментарии к этому сообщению) записать время. Когда они отправляют счет, вы можете убедиться, что у них есть открытая игра, и они не отправляют счет слишком рано или слишком много.

Возможно, стоит поработать со скаляром, чтобы узнать, каков максимальный счет за секунду/минуту игры.

Ни одна из этих вещей не является необрезанной, но это поможет иметь некоторую логику не во Flash, где люди смогут ее увидеть.

3
Oli

По моему опыту, это лучше всего рассматривать как проблему социальной инженерии, а не как проблему программирования. Вместо того, чтобы сосредоточиться на том, чтобы обманывать было невозможно, сосредоточьтесь на том, чтобы сделать его скучным, удалив стимулы к обману. Например, если основным стимулом являются общедоступные высокие баллы, простое включение задержки при показе высоких баллов может значительно уменьшить мошенничество, удалив петлю положительной обратной связи для мошенников.

3
Scott Reynen

Вы говорите о том, что называется проблемой доверия клиентов. Поскольку клиент (за эти деньги SWF работает в браузере) делает то, для чего он предназначен. Сохранить высокий балл.

Проблема в том, что вы хотите убедиться, что запросы "сохранить счет" исходят из вашего флэш-фильма, а не какой-то произвольный HTTP-запрос. Возможным решением для этого является кодирование токена, сгенерированного сервером, в SWF во время запроса (используя flasm ), который должен сопровождать запрос, чтобы сохранить высокий балл. Как только сервер сохраняет этот счет, срок действия токена истекает и он больше не может использоваться для запросов.

Недостатком этого является то, что пользователь сможет отправлять только один высокий балл за загрузку флэш-фильма - вы должны заставить его обновить/перезагрузить SWF, прежде чем они смогут снова играть для нового балла.

2
Peter Bailey

Способ, которым пользуется новый популярный аркадный мод, заключается в том, что он отправляет данные из флэш-памяти в php, обратно во флэш-память (или перезагружает их), а затем обратно в php. Это позволяет вам делать все, что вы хотите, чтобы сравнить данные, а также обходить пост-данные/дешифрование и т.п. Один из способов сделать это - назначить 2 рандомизированных значения из php во флэш-память (которую вы не можете получить или увидеть, даже если вы запускаете флэш-захват в реальном времени), используя математическую формулу для сложения оценки со случайными значениями, а затем проверяя ее, используя та же самая формула, чтобы обратить это, чтобы видеть, соответствует ли счет этому, когда это наконец идет к php в конце. Эти случайные значения никогда не видны, также как и время транзакции, и если она длится более пары секунд, она также помечает ее как мошенничество, потому что предполагает, что вы остановили отправку, чтобы попытаться выяснить случайные значения или выполнить числа через некоторый тип шифра, чтобы возвратить возможные случайные значения, чтобы сравнить со значением оценки.

Это кажется довольно хорошим решением, если вы спросите меня, кто-нибудь видит какие-либо проблемы с использованием этого метода? Или возможные способы обойти это?

2
Vaughn

Я думаю, что самым простым способом было бы вызывать такую ​​функцию, как RegisterScore (оценка), каждый раз, когда игра регистрирует добавляемый счет, а затем кодирует его, упаковывает и отправляет в сценарий php в виде строки. PHP-скрипт знает, как правильно его декодировать. Это остановит любые вызовы прямо в скрипт php, так как любая попытка форсировать счет приведет к ошибке распаковки.

2
mathieu landry

Всякий раз, когда ваша система рекордов основана на том факте, что приложение Flash отправляет незашифрованные/неподписанные данные рекордов через сеть, они могут быть перехвачены и обработаны/воспроизведены. Ответ следует из этого: зашифровать (прилично!) Или криптографически подписать рекордные данные. Это, по крайней мере, затрудняет взломать вашу систему рекордов, потому что им нужно будет извлечь секретный ключ из вашего SWF-файла. Многие люди, вероятно, сдадутся прямо там. С другой стороны, все, что нужно, это один человек, который извлечет ключ и отправит его куда-нибудь.

Реальные решения предполагают более тесную связь между приложением Flash и базой данных рекордов, так что последние могут проверить, является ли данная оценка несколько реалистичной. Это, вероятно, сложно в зависимости от того, какая у вас игра.

2
Jan Krüger

Невозможно сделать его полностью не взломанным, так как легко декомпилировать SWF-файлы, и опытный хакер-разработчик сможет затем проследить ваш код и выяснить, как обойти любую зашифрованную систему, которую вы можете использовать.

Если вы просто хотите, чтобы дети не обманывали с помощью таких простых инструментов, как TamperData, вы можете сгенерировать ключ шифрования, который вы передадите SWF при запуске. Затем используйте что-то вроде http://code.google.com/p/as3crypto/ , чтобы зашифровать высокий балл перед его возвратом в код PHP. Затем расшифруйте его на стороне сервера перед сохранением в базе данных.

2
David Arno

Я обычно включаю "данные о призраках" игрового сеанса в запись рекорда. Поэтому, если я делаю гоночную игру, я включаю данные воспроизведения. У вас часто есть данные для воспроизведения уже для функции воспроизведения или для функции призрачных гонок (игра против последней гонки или игра с призраком чувака № 14 в таблице лидеров).

Проверка их - это очень ручной труд, но если цель состоит в том, чтобы проверить, являются ли первые 10 участников конкурса законными, это может быть полезным дополнением к арсеналу мер безопасности, на которые уже указывали другие.

Если цель состоит в том, чтобы держать список рекордов онлайн до конца времени, чтобы никто не смотрел на них, это не принесет вам много пользы.

2
Lucas Meijer

Это возможно только путем сохранения всей игровой логики на стороне сервера, которая также хранит счет внутри, без ведома пользователя. По экономическим и научным причинам человечество не может применять эту теорию ко всем типам игр, кроме пошаговых. Например, Хранение физики на стороне сервера требует больших вычислительных ресурсов, и его сложно адаптировать к скорости работы. Даже возможно, играя в шахматы, любой может сопоставить игровой процесс ИИ с противником. Поэтому лучше многопользовательские игры также должны содержать креативность по требованию.

2
placeohlder

На самом деле невозможно достичь того, чего вы хотите. Внутренние части приложения Flash всегда частично доступны, особенно когда вы знаете, как использовать такие вещи, как CheatEngine , то есть независимо от того, насколько безопасны соединения вашего сайта и браузера <-> с сервером, оно все равно будет быть относительно простым для преодоления.

1
Mark Webster

Это может быть хорошей идеей для связи с бэкэндом через AMFPHP . Это должно отговорить по крайней мере ленивых от попытки протолкнуть результаты через консоль браузера.

1
m1gu3l