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

Я говорю об игре действия без верхнего предела оценки и не проверять счет на сервере, переигрывая ходы и т.д.

То, что мне действительно нужно, - это самое сильное шифрование, возможное во Flash/PHP, и способ предотвратить людей, вызывающих страницу PHP, кроме моего файла Flash. В прошлом я пробовал несколько простых методов для создания нескольких вызовов для одного счета и завершения последовательности контрольной суммы/фибоначчи и т.д., А также обфускации SWF с помощью шифрования Amayeta 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)

Ответ 1

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

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

  • Атакующие управляют памятью выполнения 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 зла.

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

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

Ответ 11

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

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

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

Ответ 12

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

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

Ответ 13

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

Ответ 14

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

Ответ 15

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

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

Ответ 16

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

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

Приветствия, Ico

Ответ 17

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

Ответ 18

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