Защита от накруток в онлайн играх

    Это статья о том, как мы делали систему защиты браузерной HTML5 игры от взлома и подделки результатов, с какими трудностями мы при этом столкнулись, как их решали и что получили в итоге. Основной и всем знакомой проблемой таких игр является возможность написания бота, который эту игру автоматически пройдет. Разработку подобного бота облегчает тот факт, что код игры находится в публичном доступе. Ситуация осложнялась тем, что были объявлены реальные призы, среди которых iPad, билеты на концерт, USB флеш накопители и т.п.



    Статья будет полезна в основном тем, кто делает HTML5 / Flash игры и заботится об их безопасности; тем, кто платит за разработку этих игр; и немного тем, кто призван бороться с ботами. Ну и, конечно, тем, кто написал эту статью. Потому что мы надеемся, что она станет началом продуктивной дискуссии о том, как разработчики браузерных игр могут противостоять кибер-мошенникам.

    Что за игра?


    Немного о самой игре.
    К сожалению, саму игру мы показать не можем по требованию заказчика. Несмотря на все описанные ниже приемы, к сожалению, «незнание» является ключевым элементом защиты. То есть раскрытие методов в привязке к конкретной игре, существенно снизит их эффективность.
    • Тип игры: Collect & Run.
    • Примеры: всем знакомый Mario Bros. и его клоны
    • Продолжительность игры: примерно 1-2 минуты.
    • Цель игры: набрать наибольшее количество очков.
    • Основные элементы игры:
      • Персонаж.
        Главное действующее лицо, всегда движется. Может подпрыгивать и пригибаться для того, чтобы собирать бонусы и избегать препятствий.
      • Бонусы.
        Могут увеличивать очки или скорость движения персонажа. Для того, чтобы их собрать, персонаж должен подпрыгнуть.
      • Препятствия.
        Барьеры или движущиеся навстречу персонажу предметы. Для того, чтобы их избежать, персонаж должен пригнуться или подпрыгнуть. При столкновении с препятствием персонаж теряет скорость.
    • Характеристики игры, используемые при расчете результата игры:
      • Набранные очки. Увеличиваются при сборе бонусов.
      • Скорость персонажа. Уменьшается со временем. Уменьшается при столкновении с препятствием. Увеличивается при сборе бонусов.
      • Затраченное на игру время.
    • Используемые технологии:
      • Клиент: HTML5. Основание: требовалось, чтобы игра запускалась на всех устройствах. JS-framework: Pixi.js (http://www.pixijs.com)
      • Сервер: PHP, Framework: Zend
    • Цель заказчика: реклама своего бренда через игру. Игровой процесс был связан с услугами компании; логотипы, фирменные цвета и все такое прочее в наличии.
    • Игра запускалась на определенный срок, по истечению которого игроки с лучшими результатами награждались ценными призами.
    • Исходя из вышеуказанного, заказчик сразу делал упор на то, что игра должна быть защищена от подделки результатов. Заказчик дорожит репутацией. Он не хотел, чтобы после выхода игры в СМИ появилась информация, что их брендованная игра взломана.

    Что за команда?


    Мы — web-разработчики, но разработкой игр ранее не занимались. В самом начале мы родили много смешных решений. Например, мы сделали важную архитектурную ошибку — решили генерировать уровень на клиенте в браузере; а в качестве защиты уповали на обфускацию JS кода. Правда товарищи из соседних отделов говорили, что для качественной защиты придется “проигрывать” игру на сервере и сравнивать с клиентом. Но мы посмеялись тогда, что это уж очень сложно.

    Повторюсь, что главнейшим требованием было обеспечить защиту от накруток. Но наша команда решила сначала сделать так, чтобы игра в принципе работала. А разработку защиты отложили на попозже. Казалось логичным: сначала что-то делаем, и уже потом это “что-то” защищаем.

    The Проблема


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

    Мы начали с простого решения — обфускации JS кода и шифрования данных, отправляемых клиентом на сервер. Но у заказчика была убойная команда безопасности, которая за 15 минут смогла записать нереальный игровой счет, имея полностью обфуцированный код. Шифрование данных при передаче тоже не вариант — ключи лежат у клиента, и их можно легко подставить в нужное место. Так что фактически оба этих решения оказывались действенными только для очень ленивых хакеров.

    Более того, Flash-игры тоже подвержены подобному реверс-инжинирингу, и те разработчики тоже в поиске решения защиты.

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

    Советы из Интернета


    Несмотря на то, что разработано уже очень много онлайн игр, информации о методах борьбы с их взломом удалось найти крайне мало. Вот какие рекомендации мы извлекли из просторов Интернета:
    • Скрывать, защищать и шифровать игровые данные:
      • Ответственные за игровой счет переменные не следует делать в глобальной области видимости. Их рекомендуют объявлять приватными и помещать в замыкания (closure).
      • Не отсылать значения счета в открытом виде, а обязательно шифровать.
      • Шифровать адреса (uri), по которым передается счет.
      • Обфуцировать часть кода, которая ответственна за вычисление и отправку счета.
      • Присылать вместе с результатами игры лицензионные ключи и проверять их на сервере.
      • Плюсы: относительная простота реализации
      • Минусы: как уже было написано выше — взламывается за 15 минут
    • Дурачить хакеров:
      • При обнаружении накрутки счета все равно показывать хакеру в списке рекордов его результат. Пусть он думает, что дело сделано. Но остальные пользователи этого видеть не должны.
      • Когда игра определяется как взломанная, то откладывать наказание на случайный срок (например, от 1 до 3 дней). Хакер будет применять несколько методов и периодически он будет видеть, что у него получается. Но что именно получается, понять ему будет сложно, и на чем конкретно его поймали в итоге — тоже.
    • Проверять реалистичность игровых данных:
      • Проверять на сервере теоретическую возможность присылаемых значений. Например, энергия не может быть отрицательной, счет не может уменьшаться, позиция игрока всегда увеличивается и т.п.
      • Присылать данные игры на сервер и сравнивать данные с теми же данными других пользователей. Например, если игрок сделал 200 выстрелов и достиг счета 200000, а остальные игроки сделав 200 выстрелов достигают счета 5000, то это повод усомниться в честности игры.
      • Удалять игры, которые длились менее (более) определенного времени.
      • Плюсы: относительная простота реализации
      • Минусы: не дает полной защиты, добавляет лишние 5-10 минут на организацию взлома
    • Организационно воздействовать на аккаунты:
      • Добавить важности аккаунту, чтобы было жалко его потерять. Например, чтобы поиграть в эту игру с реальными призами, надо сначала достичь чего-то в других играх без призов.
      • Сделать регистрацию аккаунта платной.
      • Банить по IP хакеров при самой первой попытке взлома. Вообще не давать им возможности разобраться.
    • Эмулировать игру на сервере:
      • Сделать 'instant replay' на сервере. После прохождения уровня присылать данные, по которым восстанавливаются события в игре и заново рассчитывается ее результат. Затем это все сравнивается с тем, что прислал игрок, и если разница большая, то это хак.
      • Плюсы: дает большую степень защиты
      • Минусы: события, отправляемые в конце игры также могут быть подделаны

    Мы провели мозговой штурм и тоже выработали много идей. Были удачные, были и не очень. К разряду не самых удачных можно отнести, например, вывод капчи “до”, “во время” и “после” игры. Или, допустим, получение скриншотов во время игры и отсылка их на сервер для проверки. Далее описаны наиболее интересные из реализованных методов.

    Эмулятор игры


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

    Для этого мы стали генерировать игру (расположение бонусов и препятствий) на сервере и
    отправлять на сервер не конечный результат игры, а только события, которые в ней происходили: столкновения с препятствиями, бонусами и нажатия клавиш. Для каждого события мы знали время, координаты, нажатые клавиши или бонусы/препятствия с которыми игрок столкнулся.

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

    Другой вариант: обрабатывать события на сервере и немедленно отправлять результаты события на клиенте. Но при этом возникает очень большой трафик между сервером и клиентом, увеличивается время отклика игры и резко возрастает нагрузка на сервер. Так работают, например, MMO игры. Но для небольшой Collect & Run игры мы посчитали это нецелесообразным.

    Особо хочется отметить тот факт, что устройства, на которых запускалась игра, имели разную производительность. На быстрых устройствах игра шла плавно, на медленных — рывками. Из-за этой разницы нам пришлось отказаться от привязки ко времени во время эмуляции. Вместо этого мы рассматривали события игры как нечто, происходящее в некоторых координатах. Например, сначала мы рассматривали прыжок за бонусом как “нажатие кнопки вверх на 10-ой секунде, столкновение с бонусом на 12-той секунде”. Но нам более подошло следующее: “нажатие кнопки вверх при Х-координате игрока равной 1000, столкновение с бонусом при Х-координате игрока равной 1100 и Y-координатой игрока равной 300”. В таком случае и быстрое и медленное устройства эмулировались более-менее одинаково.

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

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

    Анализатор игры


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

    1. Координаты столкновения.
      Столкновение с препятствием или бонусом произошло в браузере на клиенте в точке, где этот предмет был сгенерирован на сервере.
    2. Увеличение позиции персонажа.
      Позиция персонажа в игре должна увеличиваться со временем. Уменьшаться или оставаться одинаковой она не может.
    3. Персонаж достиг конца уровня.
      Максимальная позиция персонажа не превышает длины уровня, сгенерированной на сервере.
    4. Длительность игры.
      Уровень физически невозможно пройти менее чем за одну минуту. Поэтому игры, прошедшие за 30 секунд или за 2 минуты, считаются взломанными.
    5. Контроль индикаторов скорости и энергии.
      Значения индикаторов в браузере на клиенте должны соотноситься с игровыми событиями (сбор бонусов, столкновения с препятствиями). При взятии некоторых бонусов скорость персонажа увеличивается, при столкновении с препятствиями — уменьшается. Также сбор некоторых бонусов увеличивает набранное игроком количество очков. Зная какие предметы собрал игрок, можно вычислить на сервере, какие у него должны быть значения: скорости и суммы очков.
    6. Прыжок перед взятием бонуса.
      Бонусы висят высоко, чтобы их собрать персонаж должен подпрыгнуть. Тут проверяется, а был ли прыжок перед взятием.
    7. Прыжок перед препятствием.
      Для того, чтобы избежать столкновения с препятствием, лежащим на земле, персонаж должен подпрыгнуть. Для каждого препятствия проверяем, прыгнул ли игрок до препятствия (нажатие кнопки прыжка) и перекрыла ли его траектория прыжка.
    8. Правильные клавиши.
      Проверка нажатия строго определенных клавиш: “вверх” и “вниз”. Если нажималось что-то другое, то это подозрительно.
    9. Бонусы и препятствия собираются один раз.
      Пользователь может собрать один бонус (или препятствие) не более одного раза.
    10. Столкновения на клиенте.
      Сравнение столкновений, произошедших в браузере на клиенте и полученных на эмуляторе.
    11. Столкновения на эмуляторе.
      Сравнение столкновений, произошедших на эмуляторе, но не произошедших в игре. Этот метод введен для того, чтобы иметь разные веса этого и предыдущего методов. Мы посчитали, что если есть столкновение на эмуляторе, но нет в реальной игре, то это менее подозрительно, чем когда есть столкновение в реальной игре, но нет на эмуляторе.
    12. Взятие ложных элементов.
      При генерации игры мы добавили несколько бонусов, взять которые в игре невозможно. Например, они находятся чуть выше, чем может прыгнуть персонаж; или есть два бонуса, находящихся рядом, но физически можно собрать только один из них. И мы проверяем, попался ли хакер на приманку и взял ли он эти бонусы.
    13. Анализ “отпечатков пальцев”.
      До начала игры при регистрации и логине игрока мы собираем информацию о клиенте (плагины браузера, http заголовки, ip, установленные шрифты, размер и цветность экрана). Это не помогает нам понять, была ли игра взломана. Но зато в случае, когда администраторы помечают игрока как хакера, анализатор сканирует всех игроков в системе и находит похожие “отпечатки”. Тем самым можно с определенной вероятностью обнаруживать хакеров, которые пробуют ломать игру под одним аккаунтом, и играть “чисто” под другим.

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

    Анализатор при работе выставляет каждому методу значения от 0 до 1 (0 — игра вне подозрений, 1 — тест полностью провален) и в конце вычисляет “Индекс подозрительности игры” (тоже от 0 до 1).
    Этот индекс используется для автоматической пометки игры. Если он больше порога, то игра считается взломанной. Конкретное пороговое значение подбирается опытным путем, у нас оно получилось 0.4.

    Администрирование доказательств


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

    Для этого в админке мы сделали 4 страницы.
    1. Информация об игре — Эмулятор
      Таблица с реальными и эмулированными событиями выбранной игры. Столбцы следующие:
      • тип элемента (бонус, барьер)
      • X- и Y-координаты элемента
      • время на клиенте
      • X- и Y- координаты персонажа (на клиенте)
      • факт столкновения персонажа и элемента (да, нет)
      • X- и Y-координаты персонажа (эмулированные)
      • вероятность столкновения в указанное время на клиенте
    2. Информация об игре — Анализатор
      Общий индекс подозрительности игры и таблица с результатами анализатора по каждому методу.
    3. Анализатор
      Показывает таблицу вообще всех подозрительных игр, исходя из порога подозрительности (0 — нет подозрений, 1 — точно взломали). По опыту у нас получилось значение 0.4.
    4. Страница игрока
      Добавили в профиль игрока “Индекс подозрительности игрока”. Он вычисляется на основе индексов подозрительности всех его игр.

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

    Как все прошло



    Анализировать топ игроков через несколько дней после запуска игры было весьма занятно. Один взломщик пошел по простому пути и собрал все элементы, но ни разу не прыгнул. Он также собрал все “ложные” элементы. Другой “чемпион” эволюционировал последовательно. Сначала у него было с десяток честных игр, затем — очень много “пустых”. А в самых последних играх индекс подозрительности зашкаливал. Некоторые “победители” проходили игру менее чем за 10 секунд. Кое-кто играл в игру всего один раз и сразу попадал в топ. Это, кстати, можно использовать как метод анализатора — мало кто способен с первого раза сделать максимум. Были “рекордсмены” за одну секунду набиравшие нереальное количество очков. И так далее. Все они были заблокированы и до реальных призов не допущены. Жалоб от них не поступило.

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

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

    Заключение


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

    А что думаете вы, хабровчане? Поделитесь своими соображениями и подходами к защите онлайн игр.
    Enterra 41,81
    Компания
    Поделиться публикацией
    Комментарии 69
    • +2
      Уровень физически невозможно пройти менее чем за одну минуту. Поэтому игры, прошедшие за 30 секунд или за 2 минуты, считаются взломанными.

      Что-то не сходится…
      • 0
        Согласен, я с не совсем точно выразился. Уровни создаются такой длины, чтобы их можно было пройти до конца примерно за 1 минуту, плюс/минус несколько секунд. Поэтому большие расхождения подозрительны.
        • +2
          С нижней гранью я согласен, но вот с верхней — нет. Игрок может быть медленным, может быть падение фпс, игры или вообще игрок афк, что тогда?
          • +1
            Насколько я понял, игрок постоянно бежит — остановить его нельзя.
            • +2
              Я привел общие случаи, в частности для этой игры — это падение фпс и зависание браузера (No response) с предложением подождать или закрыть.
            • +3
              Персонаж бежит постоянно (внешне это выглядит как будто он расположен возле левого края экрана, а на него справа налево «бежит» уровень). Падение фпс мы тоже учитываем — пропускаем фреймы. Так что даже с малым фпс игра идет примерно одно и то же время как и с 60 fps.
        • +1
          Хакер может взломать систему оповещения о событиях и она будет посылать на сервер «правдивые» данные.
          • +1
            Так и очков за такие «честные» данные будут давать честно и мало, разве нет?
            • 0
              Честно и мало, но можно достичь максимально высокого «честного» результата и победить.
            • +2
              Как раз для этого и было написано несколько методов обнаружения читеров для анализатора. Например, хакер может и не догадаться как работает «Взятие ложных элементов» и будет отсылать данные о сборе всего подряд.
              Мы придумывали эти методы исходя из того, что все данные от клиента ненадежные.
              • 0
                Понял. Ложные элементы — звучит интересно. Можно, пожалуйста, детальней о реализации этого метода? Я себе это представляю так, что есть элементы, которые не видны юзеру, но имеют те же свойства, что и собираемые. Если юзер собрал все такие элементы — значит «читил».
                • 0
                  Элементы юзеру как раз видны, но до них персонаж не допрыгивает — они чуть выше находятся. И при нормальной игре они никогда не собираются. А бот может просто все собрать, не обратив внимание.
                  После генерации уровня и до отправки уровня клиенту анализатор добавляет парочку таких элементов и запоминает их id. После игры смотрим: если, например, элемент с id = 421 собран, то значит чит.
            • +2
              Ну раз уж вы собираете данные с клавиатуры, то можно сделать расчет равномерности нажатий, у бота (если только он специально не заточен) нажатия будут более равномерны, чем у человека.
              • 0
                думаю, сложнее выявить из-за неравномерности производительности устройств. Разве что привязать к каким-то вначале полученным калибровочным значениям…
                • 0
                  Это решается элементарным добавлением рендома в интервал времени между выполнением команд ботом.
                • +6
                  До разработки этой игры gamedev представлялся нам чем-то не понятным.
                  Нескромный вопрос: а заказчик был об этом в курсе, когда делал заказ?
                  • 0
                    У компании опыт разработки игр есть. У конкретной команды — не было. Тем не менее, считаю, что справились мы неплохо.
                    • +2
                      Вполне себе обычный отечественный бодишоп)
                      Продают заказчику кого могут, под вывеской «большой и успешной компании с богатым опытом».
                      А потом эти ребята клепают велосипеды на ровном месте, т.к. банально не знают как эти стандартные проблемы решают те кто «в теме».

                      Не поймите неправильно, я не хочу никого обидеть, сказать, что ребята плохо справились. Все же работает и вроде заказчик доволен.
                      Просто по статье же видно, что мыкались по разных углам не зная как решать типичную проблему.
                      А так, к сожалению, работают 99.9% бодишопов.
                      • +5
                        Да, кстати, «как эти стандартные проблемы решают те кто «в теме».» — поделитесь, как описанную задачу могли бы решить те, кто в теме?
                        • 0
                          Толсто тролите. Какой секрет вы рассчитываете тут услышать?
                          Все варианты давно известны и боле менее расписаны в статье.
                          Но в целом, те кто «в теме» например не стали бы даже пытаться рассчитывать на такие глупости как обфускация клиента и шифрование пакетов. И не смеялись бы над просчетом игры на сервере, ибо это вообще единственный способ максимально защитить игру.
                          Именно такие моменты и показывают уровень.
                  • +2
                    Как все эти методики защитят от атаки «в лоб»? Бот, используя знание обо всем уровне, может заранее рассчитать точные моменты, которых нужно подпрыгнуть или пригнуться, чтобы набрать максимальное количество прелестей, при этом вы не сможете отличить его от просто экспертного игрока, который прямо гроссмейстер в вашей игре — ведь бот будет честно отправлять KeyboardEvent. Можно еще бесполезные прыжки и приседания делать на участках, где они не смогут повредить запланированным точкам.

                    И как быть в таком случае?
                    • +1
                      Конечно, непросто будет различить гроссмейстера и бота. Надеюсь, что коллеги подскажут еще другие методы обнаружения читеров.

                      Сейчас я вижу несколько вариантов, которые увеличивают вероятность:

                      1) Уровень каждый раз генерируется заново.
                      2) Скорость персонажа периодически изменяется в зависимости от столкновений с препятствиями и уровня энергии. Так что тут надо будет физику игры сэмулировать хитрее, а не просто жать кнопку UP за 20 пикселей до каждого бонуса.
                      3) Можно использовать базу данных уже сыгранных игр, и слишком уж идеальные забеги брать на карандаш.
                      4) Вероятно, для запуска бота будут нажаты некоторые клавиши, которые отправятся на сервер. Можно будет это словить.
                      5) Этот хакер мог уже быть замечен в других нечестных играх. Можно будет проверить его через анализ «отпечатков пальцев».
                      • +1
                        Я исхожу из того, что бот — это не внешняя программа, а Greasemonkey-скрипт или расширение браузера. Т.е. бот имеет полную и безраздельную власть над браузером, что полностью соответствует действительности.

                        1) я посмотрю структуру уровня в памяти. Залезть внутрь closure не проблема.
                        2) зачем? я ведь могу использовать вашу же физику со всеми ее тонкостями реализации.
                        3) это да, но что плохого в идеальных забегах? :) для правдоподобности, бот может поднимать свой уровень постепенно.
                        4) это не проблема — бот может или запускаться через меню или кнопку на тулбаре, или по событию загрузки страницы, или просто перехватывать нажатия клавиш и не спускать их на обработку скриптам страницы вовсе :)
                        5) «отпечатки пальцев» можно ведь и рандомизировать — например, переопределить некоторые свойства navigator и возвращать случайные значения, сгенерированные заново каждый раз перед загрузкой страницы. Или добавлять рандомные биты в canvas. Или перетасовывать местами navigator.plugins, или прятать-добавлять некоторые плагины и их mime-типы. Т.е. можно сделать неограниченно много вариантов отпечатка, на самом деле. Есть и обратный подход — притворяться чем-то стоковым и популярным. Например, последним Safari на последней iOS на последнем iPhone. Конфигурации у всех одинаковые, железо у всех одинаковое, софт одинаковый, фингерпринт одинаковый, отличить хакера без бана кучи невинных пользователей Apple не получится.
                        • +1
                          Надо попробовать придумать еще варианты защиты. Очевидно, что есть понимание проблемы. Есть мысли с какой еще стороны можно к этому подступиться?
                          Предлагаю хотя бы тезисно это оформить. Либо выйти на решения через имеющиеся ограничения (типа, «доверия ответам игрока нет» и т. п.).
                          • 0
                            Я обычно с обратной стороны баррикад, поэтому мне тяжело предложить что-то, с чем я бы не смог справиться :) Абсолютная защита точно и гарантированно невозможна, какими бы вы техниками не пользовались.

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

                            Вот, кстати да. Вы можете ограничивать число возможных игр. Например, одна игра с одного IP не чаще, чем раз в два часа. Правда, я бы или не стал играть в такую игру вовсе, или записывал бы игровую сессию на видео с аннотациями нажатых клавиш, чтобы потом, используя эту запись, построить модели и обкатывать их позже, в том числе, возможно, через всяческие прокси.
                            • +1
                              Есть мнение, что если вы в состоянии сделать такую систему с видеокамерой, и чтобы еще в реальном времени жать на физические кнопки клавиатуры, то вам этот «краденый» айпад не очень-то и нужен.
                              • 0
                                Ну зачем сразу с видеокамерой и физическими кнопками? Это если у нас вместо браузера игровой автомат, в который не разрешают влазить. А если у нас именно браузер, то нет ни малейшей проблемы анализировать рендер элемента, в который отрисовывается игра, и отправлять документу свои собственные синтезированные события — в самом худшем случае. И да, он в таком случае не «краденный», а честно заработанный :)
                                • 0
                                  Я не специалист, но есть ведь способы отличить события «в документ» от настоящего ввода пользователя. Вон гугл даже капчу сделал с одной кнопкой «Я не робот».
                                  • 0
                                    Нет, таких способов на самом деле нет. В документации MDN по EventTarget.addEventListener приводится пример приватной сигнатуры, в которой присутствует параметр wantsUntrusted. Он как раз позволяет отличить синтетическое событие, созданное контент-скриптом, от «настоящего», созданного хромом. У самой страницы такой привилегии нет, для нее все события, вне зависимости от того, кем они были созданы — настоящие. С другой стороны, так как я изначально говорю о том, чтобы бот был расширением браузера, то у бота привилегии хрома есть в любом случае.

                                    Принцип работы однокнопочной капчи гугла в немного другом. «Чекбокс» на самом деле собран из нескольких div-ов со сложными стилями и обработчиками событий, которые просто выглядят, как чекбокс. Объект рекапчи собирает информацию о движениях мыши, скроллах, нажатиях клавиатуры и т.д. Операция подтверждения капчи многоэтапная и включает в себя выполнение в контексте страницы какого-то кода, который присылает сервер. Как минимум — это проверка того, что «браузер» умеет выполнять javascript. На практике, скорее всего, это или какой-то простой proof-of-work, или анализ окружения — всяких объектов типа Components.interfaces в Firefox — на предмет того, что эти объекты действительно работают; или же и то, и другое вместе.

                                    Поэтому капча гугла, скорее, должна бы называться «я не глупый робот, который посылает mouse click ровно в середину капчи, даже не передвинув туда курсор».
                                    • 0
                                      есть ведь способы отличить события «в документ» от настоящего ввода пользователя
                                      Хороший вопрос, ведь если можно будет отличить реальный ввод, то это сделает невозможным автоматическое тестирование, в крайнем случае которого успешный бот может, например, проверять игру на сложность, а менее успешный — на проходимость.
                              • 0
                                Ну и да, вы не можете доверять никаким действиям игрока. Все данные, которые приходят на ваш сервер, могут и будут подделаны, но zero-trust в этом случае не защитит от бота. Капчу показывать бесполезно — всевозможные сервисы распознавания капчи автоматизируют процесс за сущие копейки (это в среднем 1$ за тысячу капчей), капча — не выход. Бан по IP в случае ценных призов тоже не вариант, прокси стоят в среднем одна за 0.50$/мес.
                            • +1
                              >Конечно, непросто будет различить гроссмейстера и бота
                              Мне кажется, если будет получен бот, который успешно пройдёт все ваши проверки, то это гроссмейстерский бот. Получается, приз получит гроссмейстер — а в какой сфере гроссмейстер (программирование или игры), уже не так важно — награду получит достойный.
                              • 0
                                Да, именно так :) На сайтах типа codingame.com даже пропускается место с встраиванием в браузер — просто надо написать хорошего бота.
                                • 0
                                  Мы себя тоже такой идеей успокаиваем. :) Но вот заказчику такой вывод сложно будет объяснить.
                                  • 0
                                    хмм… я вот подумал. Такой гроссмейстерский бот не будет отличим от игрока, по крайней мере — онлайн. А вот если всех победителей пригласить на офлайн-соревнование, и там они должны будут показать хотя бы наполовину такие же результаты — то они не боты.
                                    • 0
                                      Для серьезных игр — да, хороший вариант, отсекает ботов сразу. А вот касаемо казуальных онлайн-развлекалок — громоздкое решение имхо. Много ли народа согласится приехать лично побороться даже за iPad (не говоря уже о usb-флешках.)
                                      • 0
                                        Я подумал об альтернативе — в прямом эфире стримить изображение клавиатуры и нажимаемых на ней кнопок, и объединить это с полным изображением экрана. Модераторы затем смотрят, действительно ли логические нажатия клавиш предваряются физическими. Минус — нужно, чтобы у испытуемого была вебкамера. Плюс — достаточно сложно подделать. Если уровень, который будет проходиться, заранее не известен, то придется сделать систему, которая синтезирует изображение клавиатуры и рук, а сделать это в реалтайме… Думаю, награду в таком случае автор точно заслужил :)
                              • 0
                                вы предлагаете решить задачу в общем случае? Тогда решение сможет отличать искусственный разум от человеческого. Это известная проблема — Тест Тьюринга . Я думаю достаточно сделать стоимость подделки результатов игры значительно выше стоимости призов. С этим, команда успешно справилась.

                                У меня есть головоломка (Triplex), которая в своём javascript исходнике на клиенте хранит уровни: каждый следующий зашифрован кодом решения предыдущего. Самый простой взлом — написать свой решатель уровней.
                                • 0
                                  Если приз стоит 1000$, а бота можно написать за неделю свободного времени (т.е. за 30 часов), то с учетом двухкратной оплаты работы во внеурочное время, разработчик должен получать меньше 3000$ в месяц, чтобы затраты окупились.
                                  • 0
                                    Дык ведь челлендж же! Челлендж дороже любых денег.
                              • +1
                                Тоже решали аналогичную задачу, только игра была в жанре Tower Defense, что накладывало свои особенности.
                                Тоже пришли к сбору данных о действиях игроков.
                                В итоге ловили нечестных игроков на одинаковых во многих сессия координатах кликов, на слишком быстрых действиях (разнца между действиями 3мс), на одинаковых отсылаемых значениях.
                                Правда анализировали действия самостоятельно — на автоматическую систему проверки никто времени не закладывал.
                                • +1
                                  А как вы доказывали, что этот игрок нечестный? Как вы оформляли результаты?
                                  • 0
                                    Мы предоставляли заказчику список нескольких первых десятков пользователей с пометками о наших подозрениях.
                                    Исключенные из рейтинга пользователи обычно не обращались, а тем кто писал, давали ответы поподробнее, но без конкретных цифр.
                                • +1
                                  Но ведь поставленная задача в принципе не разрешима. Если вся логика игры у клиента, то он может накрутить так, чтобы это выглядело честно. А JS полностью под контролем пользователя. В крайнем случае можно и «честного» бота сделать — такого, который будет неотличим от пользователя.
                                  • +1
                                    Тем не менее браузерных игр много, и они как-то живут. А Flash ненамного сложнее JS в накрутке.
                                    В конце статьи я написал, что у сервера все же есть нечто, что недоступно клиенту-мошеннику — база данных сыгранных игр. Вот туда надо копать, если задача в принципе не разрешима.
                                    «Честный» бот с точки зрения хакера может получиться далеко не типичным со стороны сервера.
                                    • +1
                                      Но бремя доказательства лежит именно на вас, а не на хакере. Если бот использует тот же интерфейс для игры, что и человек, он неотличим от человека. Логичность-алогичность действий — это субъективные метрики, и «мне кажется, что это играет не человек, уж больно у него хорошо получается» — ну извините, это никуда не годится.
                                      • 0
                                        В любом случае надо постараться улучшить текущее положение дел по проблеме. Сейчас сделано как сделано. Но в будущем нам бы хотелось расширить возможности по отлову. Было бы здорово услышать предложения по этому поводу. Смею предположить, что знаний хватает. Или вправду — не разрешимая задача?
                                        • 0
                                          Задача неразрешима по определению. Вам требуется контролировать пользователя, который полностью контролирует ваши знания о нем.
                                          • +2
                                            Можно устраивать финал в реальной жизни. Где видно кто как играет на контролируемом окружении.
                                            • +1
                                              Единственный кандидат в здравые решения, кстати.
                                        • 0
                                          Браузерные игры основаны на временных затратах и переводе времени в деньги. Боты несомненно дают в них профит, но как правило донат все равно позволяет обогнать бота, да и разработка бота тоже стоит времени / денег.
                                        • +2
                                          Я думаю стоит исходить из того, что сложный бот имеет некую «цену» создания. Чем больше проверок, тем «дороже» будет бот. Если «цена» написания бота будет заметно «дороже» возможного выигрыша, то смысла в таком боте, кроме академического, не будет.

                                          Можно провести аналогию с фальшивоменотчеством. Деньги можно подделать, но средства защиты стремятся сделать стоимость подделки неретабельной.
                                          • +2
                                            Вы недооцениваете влияние увлеченности :) Сложного бота можно сделать из принципа, чтобы показать, что «невзламываемая игра» все-таки поставлена на колени, даже несмотря на то, что профит от подобного решения может быть чисто психологическим.
                                            • 0
                                              Сделать трудновзламываемую игру — тоже челендж в некотором смысле. :)
                                              • 0
                                                К сожалению, это невыполнимый челлендж. Вы можете усложнить взлом, например, написав игру на C и OpenGL, и скомпилировав ее в asm.js. Или можете сделать PPAPI/NPAPI-плагин, который будет загружать шифрованный пакет с логикой игры и играть ее. Но все это удаляет вас от, собственно, делания игр. Вы меньше занимаетесь играми и больше занимаетесь побочными задачами. И все ваши ухищрения не имеют смысла, пока бот может просто сесть за клавиатуру, посмотреть в монитор и пройти игру так, как прошел бы ее человек с нечеловеческими способностями к прогнозу и реакции.
                                                • 0
                                                  Допустим, что это [пока] невыполнимый челлендж.
                                                  Есть ли предложения (для ближайшего будущего) какие принимать допущения для подобных проектов?
                                                  Иными словами, если будет снова предложение написать браузерную игру с реальными призами, то как видится процесс?
                                                  Не хочется думать, что придется отказаться с формулировкой «невыполнимо».
                                                  • +2
                                                    Могу только подсказать несколько аспектов, которые могут усложнить анализ при правильном стечении звезд обстоятельств.
                                                    1. Пишите не на JavaScript, а на языке со статической типизацией, который может компилировать LLVM — т.е. C, C++, D и т.д. Полученный проект собирайте emscripten-ом в asm.js-овый бандл, предварительно включив LTO и IPO. Проследите, чтобы у вас не было именованных экспортов.
                                                        + будет работать намного (на порядок) быстрее, чем типичная реализация руками непосредственно в JS;
                                                        + исходник будет крайне сложен для анализа, без довольно специфичного опыта реверс-инжениринга выхлопа кодогенератора биткода LLVM не обойтись;
                                                        + внутреннее состояние игры раскрывается, но зачастую не в той мере, чтобы позволить модификацию;
                                                        – вы все равно зависите от браузера в том, чтобы доставить ваши данные к серверу

                                                    2. Используйте ECDSA и подписывайте состояния объектов, а потом в случайные моменты проверяйте правильность подписей. Можно скомбинировать с кодом Рида-Соломона, чтобы словить модификацию подписей или содержимого и потом уже придумать, что делать.
                                                        + может обмануть читера, если он первым делом полезет менять память, а уже потом запоздало подумает
                                                        – накладно с точки зрения производительности
                                                        – трудно реализовать правильно

                                                    3. Как вариант, вместо предыдущего пункта — шифруйте все состояние в памяти чем-то типа AES128CTR, чтобы иметь возможность параллельной расшифровки блоков.
                                                        + читеру придется писать декриптор
                                                        + возможно, придется лезть в дебри реализации asm.js JIT и вставлять туда свои заглушки, чтобы дампить расшифрованную память
                                                        + ключ можно генерировать на ходу
                                                        – сгенерированный ключ придется хранить открытым текстом
                                                        – будет работать медленно. возможно, имеет смысл шифровать не всю память вообще, а какой-то отдельный объект, или перемежать шифрованные и нешифрованные блоки
                                                        – нужно будет писать свой препроцессор, потому что любые обращения к памяти нужно будет обернуть в криптор;

                                                    4. Используйте secure web socket-ы для связи с сервером.
                                                        + сложнее отследить и перехватить
                                                        + сложнее модифицировать
                                                        – может не работать по ряду причин — файрвол, прокси, настройки приватности, оргия сатанинских котят, запрет SSL

                                                    5. Деструктуризируйте графику. Если рисуете плоские объекты, не используйте DOM, рисуйте сразу на <canvas>. Если используется векторная графика, разверните все SVG-группы, пусть сцена будет просто одноуровневой мешаниной безье-кривых, а группировку держите у себя в памяти. Если используете объемную графику, рисуйте прямыми вызовами WebGL.
                                                        + для отслеживания состояния придется анализировать картинку
                                                        + emscripten дает эти плюшки из коробки
                                                        – обновление групп объектов будет менее эффективным

                                                    Эти приемы позволят усложнить анализ и корректировку поведения программы в свою пользу, но ни один не поможет со 100% уверенностью. Просто при приеме заказа на «невзламываемую игру», уведомите заказчика, что полностью от взломщиков защититься невозможно даже теоретически, но даже пункт №1 из моего списка позволит вам отсечь 99% «казуальных читеров» с минимальными затратами и ощутимыми профитами, а вот стоит ли игра свеч, чтобы бодаться с оставшимся 1% — решать заказчику.
                                                    • 0
                                                      Достаточно древний пример того, как выглядят 3D-приложения после emscripten.
                                                      • 0
                                                        Огромное спасибо за подробный ответ! Правда это выглядит на порядки сложнее, чем мы умеем сейчас. Но! Знать перспективное направление в решении проблемы — уже мотивирует копать.
                                                • 0
                                                  Вот, кстати, идея. Дать нечестному игроку ощущение что игра уже взломана и ничего делать больше не нужно. :)
                                                  • 0
                                                    Ага, похожее есть в статье:
                                                    При обнаружении накрутки счета все равно показывать хакеру в списке рекордов его результат. Пусть он думает, что дело сделано. Но остальные пользователи этого видеть не должны.

                                                    :)
                                            • +1
                                              Я думаю что при наличии существенного по цене приза даже все проделанное Вами не поможет
                                              • 0
                                                Проблема в том, что бота можно написать, он может даже как человек кликать и давить на кнопки. Сам я писал такого бота для флеш игры, где надо было запоминать порядок зажигания цветных элементов и повторять последовательность. Спокойно ставил его играть на ночь и к утру он неспеша накликивал топовый результат. Обвинить меня в нечестности в принципе очень сложно, если бы захотел — смог бы сделать и случайные интервалы и координаты и все что угодно. Написать бота было несложно, пару вечеров и все. Видел недавно похожего бота на OpenCV.

                                                Тоже самое в волхаком на десктопе — его может вычислить только человек и то с определенной статистикой на руках и опытом, программно его не выщемить.
                                                • 0
                                                  Не обязательно использовать тяжелую артиллерию в виде OpenCV, для многих простых игр проще написать скрипт за 5 минут с помощью Sikuli
                                                • +1
                                                  По-моему, тут имеет место гонка средств нападения и защиты, соответственно нужно не столько защищаться, сколько распознавать и классифицировать новые схемы(соответственно, не столько нападать, сколько скрывать механизм нападения).

                                                  Ситуация аналогична гонке вирусов и антивирусников:
                                                  В: исполнить код
                                                  А: помешать исполнить код
                                                  В: исполнить код
                                                  А: распознать В
                                                  В: скрыть себя от А
                                                  А: исполнить В в песочнице
                                                  В: сделать использование песочницы ресурсоемким(proof-of-work)
                                                  А: исполнить В в песочнице
                                                  В: детектировать песочницу
                                                  А: обмануть детектор песочницы В

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

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

                                                  Следовательно, В продолжает работу даже после того, как А его распознает, и даже после того, как узнает, что его распознали… И только ресурсоемкость может заставить А остановить песочницу с В. В же с одной стороны выгодно работать в песочнице: на него тратятся ресурсы А, с другой: выгодно только если знать, в песочнице он или нет, потому как если В будет действовать одинаково, то выдаст свои методы и цель.

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

                                                  То есть проблема в общем виде неразрешима, поскольку аналогична тесту Тьюринга (агента) и детектированию виртуальности(среды): сервер не может распознать бота выше некоторого уровня, но и бот не может знать был ли он распознан, поскольку не знает уровня сервера.
                                                  Но поскольку имеем дело с гонкой, то есть опережающая и отстающая сторона.
                                                  • 0
                                                    Если все дело в глобальных результатах и призе, то проблему вовсе не обязательно решать так основательно на мой взгляд. Можно же просто сделать запись реплеев и возможность их воспроизведения. Никакой автоматизации или чего то подобного не нужно. Просто с каждым результатом на сервер присылается файл реплея и хранится. Пользователю показывается его результат сразу, но в глобальной таблице рекордов висит надпись «Обновляется раз в пару дней». И раз в пару дней специальный человек берет лучшие 10 игр и просматривает их реплеи. Если в них все хорошо — заносит их в глобальный лидерборд.

                                                    Конечно, такой подход подразумевает, что в глобальном лидерборде будут только 10(или 100) человек отображаться, а не все, но так ли это страшно? В конце концов можно показывать помимо главного лидерборда и, к примеру, «среди друзей» без модерации да и просто свой счет без модерации. Самое интересное в таком подходе то, что игрок сразу видит и понимает, что результат модерируется, а значит и желания взломать будет намного меньше и хакеров будет очень мало.

                                                    Да и по поводу ботов — их неуловить. Если взломали протокол или игру — это одно, но если имитируют человека, то это уже очень сложно доказать будет, что это был не человек. Прошел с первого раза? Я на аккаунте друга тренировался! Идеально кликает раз в 33 мс? Я в этом не виноват, презумпция невиновности, все дела. Да и бот скорее всего будет кликать с рандомом. Но если уж очень хочется ловить в том числе и ботов, то описанный способ как никакой другой подходит и для этого. Просмотр реплея вручную может дать очень много и бота придется писать очень сложного, при этом хакеру такой писать не захочется — он же не знает как происходит модерация, но знает, что она есть. Тратить неделю на супер бота при большом риске не пройти модерацию не захочет даже опытный хакер.
                                                    • 0
                                                      >> Тратить неделю на супер бота при большом риске не пройти модерацию не захочет даже опытный хакер.

                                                      По этому вопросу есть иное мнение:

                                                      — Голубчики, — сказал Фёдор Симеонович озабоченно, разобравшись в почерках. — Это же проблема Бен Бецалеля. Калиостро же доказал, что она не имеет решения.
                                                      — Мы сами знаем, что она не имеет решения, — сказал Хунта, немедленно ощетиниваясь. — Мы хотим знать, как её решать.
                                                      — Как-то странно ты рассуждаешь, Кристо… Как же искать решение, когда его нет? Бессмыслица какая-то…
                                                      — Извини, Теодор, но это ты очень странно рассуждаешь. Бессмыслица — искать решение, если оно и так есть. Речь идёт о том, как поступать с задачей, которая решения не имеет. Это глубоко принципиальный вопрос…

                                                      © Стругацкие.
                                                    • 0
                                                      Потому что мы надеемся, что она станет началом продуктивной дискуссии о том, как разработчики браузерных игр могут противостоять кибер-мошенникам.

                                                      Мне не очень нравится определение «кибер-мошенник». Я например считаю логичным, что человек должен использоваться свои сильные стороны. У кого-то есть отличная реакция, у кого-то сутки свободного времени, а я предпочитаю использовать ум.

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

                                                      Из необычны могу вспомнить небольшую флеш-игру, которую мэйловцы делали, когда разыгрывали ключи раннего доступа к Archeage. Игрок видел N одинаковых статуй и должен был выбирать «правильную» для получения очков. Когда я посмотрел код я обнаружил, что при нажатии на сервере банально кидается рандом независимо от статуи на которую ты кликал, создавая иллюзию выбора. Это конечно не помешало создавать сотни аккаунтов и «брутфорсить», но тем не менее «иллюзия управления» очень меня удивила, т.к. игрок действительно считал что его выбор значим.
                                                      • 0
                                                        а почему вы решили, что там был рандом? может, сервер запоминал, какая статуя «выигрышная», и при щелчке смотрел, по ней ли нажали. Хотя, с другой стороны, абсолютно нет никакой разницы, кидать рандом ДО выбора статую или ПОСЛЕ этого — результат абсолютно не изменится.

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

                                                      Самое читаемое