Защита от читов для браузерной игры xmlhttp/js/perl/php

Допустим, в браузерной игре выполнение какого-либо действия (для простоты, скажем, кто-то нажимает на ссылку, которая увеличивает их счет на 100), переходя по этой ссылке, например, с URL-адресом increase_score.pl?amount=100 что это за предупреждение, если кто-то просто отправляет запросы на веб-сервер для выполнения этой команды:

  1. Снова и снова, не выполняя задачи по нажатию на ссылку и
  2. Отправка ложного запроса на сервер, где значение установлено на что-то вроде 100000.

Я в курсе проверки HTTP_REFERER однако я знаю, что люди могут обойти это (не знаю, как именно), и кроме каких-либо ограничений, проверяющих второй вариант, я немного озадачен. Кто-нибудь когда-нибудь испытывал подобные проблемы? Решения?

10 ответов

Решение

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

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

Например: на SO, когда кто-то голосует за ваш вопрос, это не посылается как команда для повышения вашей репутации. Веб-приложение просто говорит серверу, что пользователь X проголосовал за вопрос Y up. Затем сервер проверяет данные и присваивает баллы, если все проверено. (Не сказать, что ТАК игра, но необходимая логика похожа.)

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

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

НЕПРАВИЛЬНЫЙ ПУТЬ:
Клиент: Игрок Стив говорит, чтобы дать Игроку Стиву один миллион очков.
Сервер: Хорошо!

ПРАВИЛЬНО:
Клиент: Игрок Стив говорит, чтобы дать Игроку Стиву один миллион очков.
Сервер: Что ж, позвольте мне сначала проверить, разрешено ли игроку Стиву в данный момент давать один миллиард очков... ах. Он не Пожалуйста, покажите это сообщение "Go Fsck Yourself, Cheater" игроку Стиву.

Что касается определения того, кто вошел в систему, это просто вопрос передачи клиенту куки с чертовски почти невозможным для угадывания значением, которое вы отслеживаете на сервере - но я предполагаю, что вы знаете, как поступить с управлением сессиями.:-) (А если нет, то Google ждет.)

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

HTTP_REFERER может быть подделан любым веб-клиентом.

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

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

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

Это может варьироваться по сложности в зависимости от того, как часто вы разрешаете клики.

Несколько вещей, чтобы отметить здесь.

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

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

Ben S замечательно рассказывает о том, как вы разрабатываете протоколы связи между клиентом и сервером. Разрешить отправку значений точек в качестве доверенных данных, как правило, будет плохой идеей. Желательно указать, что действие имело место, и позволить серверу выяснить, сколько очков следует назначить, если оно вообще есть. Но иногда вы не можете обойти это. Рассмотрим сценарий гоночной игры. Клиент должен отправить время пользователя, и его нельзя абстрагировать в какой-либо другой вызов, такой как "completeLevelFour". Так что же вы делаете сейчас?

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

Там очень мало, что вы можете сделать, чтобы сделать его на 100% надежным. Но вы можете сделать это очень неудобным для обмана. Рассмотрим модель безопасности Facebook (каждый запрос API подписан). Это очень хорошо и требует, чтобы злоумышленник действительно углубился в ваш клиентский код, прежде чем он сможет понять, как подделать запрос.

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

Удачи!

Токен с cookie/ сессией.

Расширяя ответ Ахмета, каждый раз, когда они загружают страницу, генерируют случайный ключ. Сохраните ключ в сеансе пользователя. Добавьте случайный ключ к каждой ссылке, чтобы новая ссылка для получения этих 100 баллов была следующей:

increase_score.pl?amount=100&token=AF32Z90

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

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

Я бы предложил сделать URL-адрес, специфичный для каждого действия. Что-то вроде:

/score/link_88_clicked/
/score/link_69_clicked/
/score/link_42_clicked/

Каждая из этих ссылок может делать две вещи:

  1. Отметьте в сеансе, что ссылка была нажата, чтобы она не отслеживала эту ссылку снова.
  2. Добавьте к их счету.

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

Это также блокирует большинство трюков CheatEngine.

Другие вопросы по тегам