Защита клиент-серверного приложения
У меня есть программа, которая отправляет/принимает запросы с сервера. Сама по себе программа не содержит какого-либо "платного" кода, он обрабатывается на сервере. Это значит, что бы обезопасить программу от кряка, нужно сделать так, что бы сервер обрабатывал запросы лишь "оригинального" продукта.
Как вариант, можно в каждом пакете хранить какой-то код, который будет проверять сервер, и исходя из этого уже делать вывод: обрабатывать такой пакет или нет. Тогда, даже при кряке клиента можно будет поменять этот код на сервере, и взломанная версия станет нерабочей (но, что мешает крякнуть оригинальный продукт еще раз).
Но, где хранить такой ключ на стороне клиента, что бы его было сложнее всего вытащить? Или есть любые другие способы обезопасить такого рода продукт? Буду благодарен за любой совет.
Ответы (2 шт):
Сервер - работает по принципу обработки запросов. Сервер не когда не отправляет клиенту сам данные. Он отвечает только на запросы. Этот принцип работает на MMORPG проектах. Структура запросов выглядит схемой. Пакет данных состоит из двух главных структур: OpCode Data
OpCode - ключ инициализации пакета (Обработчик должен понимать какой сервис вызывать для обработки запроса клиента); Data - Доп. информация пакета. Логин, пароль и иные данные.
Пишем обработчик пакета. Как видим, регистрируем пакет по ключу 0x00.
namespace NETNextCloudServer.Network
{
public sealed class GamePacketHandler
{
private static readonly ConcurrentDictionary<byte, Type> ClientPackets = new ConcurrentDictionary<byte, Type>();
private readonly IServiceProvider serviceProvider;
public GamePacketHandler(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
ClientPackets.TryAdd(0x00, typeof(ServiceAuthorized));
}
internal void HandlePacket(Packet packet, Client client)
{
LoggingProvider.Instance.Debug($"Received packet: {packet.FirstOpcode:X2}:{packet.SecondOpcode:X2}");
PacketBase packetBase = (PacketBase)Activator.CreateInstance(ClientPackets[packet.FirstOpcode], serviceProvider, packet, client);
if (packetBase == null)
throw new ArgumentNullException(nameof(packetBase), $"Packet with opcode: {packet.FirstOpcode:X2} doesn't exist in the dictionary.");
packetBase.RunImpl();
}
}
}
P.S. Код не полный. Базовый пакет - абстрактный, с одним методом. Обработчик инициализируется при подключении клиента.
Проблема решена. Обработчик не будет обрабатывать запросы, если из перечисленных (зарегистрированных пакетов) не существует.
Первое, что нужно научится делать - это идентифицировать клиента. Тут можно использовать разные пути. Например, можно использовать номер телефона или просто имя-пароль. Главное, что бы у законного пользователя был стимул использовать только его аккаунт. Некоторые американские компании иногда используют SSN (номер страховки) как пароль, его обычно никому так просто не рассказывают.
Ок, с этой частью разобрались. Теперь делаем так, что бы каждый запрос содержал этот id (идентификатор). Все запросы, которые его не содержат, сразу отсекаются.
Все запросы, которые содержат id, проходят через систему квот, которая учитывает, сколько каких запросов выполнил пользователь и логирует его ip и другие данные.
Эта система может быть встроенная в Ваше приложение, а может использоваться сторонние наработки. Если у Вас используется nginx как прокси (очень типичное дело), то можно просто писать в лог, а дальше анализировать его.
Теперь соединяем все воедино. Взломать систему можно только тремя способами
- своровать у кого то его данные подключения. Меняем просто id этому пользователю, а старый просто помечаем как забаненый и на его запросы предлагаем просто купить продукт (обижать вряд ли стоит, может пользователь не знает).
- кто то поделился своим id. Тут есть два варианта - либо просто разобраться с пользователем (может он использует с работы и с дома и это нормально). А может хоть и поделился, но готов доплатить копеечку-другую - все индивидуально.
- сломали сервер... тут уже нужно у себя разбираться.
Но остается вопрос - а как мы собственно узнаем о том, что id кто то поделился? А для этого нужно следить за кол-вом запросов. Для начала думаю подойдет любая система мониторинга логов - splank, elk, kibana (их много) Через какое то время для Вас станет очевидным, какое кол-во каких запросов является нормой. И можно будет настроить систему "alert'ов", которая будет нотифицировать, если что то пойдет не так. Вот тогда можно применить ещё один механизм - ограничение кол-ва запросов (для nginx есть плагин http://nginx.org/ru/docs/http/ngx_http_limit_req_module.html). То есть, пользователь расшарил свой id на десять друзей, но сервер продолжает выделять на них одни и те же ресурсы. Для них все работает медленно. Пользователь придет жаловаться, вот тут с ним можно и поговорить.
и на последок
обрабатывал запросы лишь "оригинального" продукта.
тут есть два пути. Первый - забить. и предоставлять API. И с настроенными лимитами вполне может быть.
Второй - заморочиться и сделать защиту. Пересылать ключи на каждый пакет (как делал скайп), проверять особенности реализации протокола (как делала ICQ), но в конце концов они от этого отказались - шкурка не стоит вычинки.