По сути, у вас есть три требования:
- не должно быть легко использовать один и тот же ключ для нескольких клиентских экземпляров,
- не должно быть легко генерировать новые действительные ключи, и
- не должно быть легко украсть ключ законного клиента.
Первая часть должна быть довольно простой: просто не позволяйте двум игрокам одновременно заходить на один и тот же сервер с одним и тем же ключом. Вы также можете заставить серверы обмениваться информацией о вошедших в систему пользователях или связаться с общим сервером аутентификации, так что даже использование одного и того же ключа для разных игроков на разных серверах одновременно не удастся. Вам также, вероятно, захочется найти подозрительные схемы использования ключа и, если вы решите, что ключ был утек, добавьте его в список запрещенных ключей.
Для второй части один из способов - просто поддерживать базу данных всех действительных выданных ключей. До тех пор, пока ключи достаточно длинные (скажем, 128 бит или более) и выбираются случайным образом (с использованием безопасного RNG), шансы того, что кому-то удастся угадать действительный ключ, по существу равны нулю. (Даже намного более короткие ключи могут быть безопасными, если вы используете какое-то ограничение скорости при неудачных попытках входа в систему, чтобы остановить попытки найти действительные ключи с помощью грубой силы.)
Кроме того, вы можете генерировать ключи, взяв любой уникальный идентификатор и добавив код аутентификации сообщения. (например, HMAC ), рассчитанный с использованием секретного главного ключа. Опять же, до тех пор, пока MAC достаточно длинный, шансы того, кто не знает мастер-ключ, сможет угадать действительный MAC для любого идентификатора, ничтожны. Одним из преимуществ этого метода, помимо устранения необходимости в базе данных ключей, является то, что идентификатор может быть любой уникальной строкой и может кодировать информацию о клиенте, для которого был выдан ключ.
Одна проблема с использованием MAC заключается в том, что официальные игровые серверы (или, по крайней мере, сервер аутентификации) должны знать главный ключ для проверки MAC, что означает, что, если серверы взломаны, главный ключ может быть утечен. Одним из способов снижения этого риска может быть вычисление нескольких MAC-адресов для каждого идентификатора с использованием разных мастер-ключей, но только хранение одного из мастер-ключей на игровых серверах. Таким образом, если этот мастер-ключ когда-либо просочится и будет использован для создания поддельных идентификаторов, вы можете отозвать его и переключиться на другой мастер-ключ. В качестве альтернативы вы можете заменить MAC цифровыми подписями , которые можно проверить, используя только открытую половину мастер-ключа.
В третьей части один из подходов заключается в том, чтобы клиент не отправлял свой ключ кому-либо, не убедившись, что получатель действительно является законным официальным сервером. Например, вы можете использовать SSL / TLS (или DTLS ) для процесса входа в систему, выпускать пользовательские сертификаты для своих игровых серверов и иметь только сертификаты доверия клиентов, выданные вами. Удобно, что использование TLS также защитит клиентские ключи (и любые другие данные аутентификации) от перехватчиков, например, в общедоступных беспроводных локальных сетях.
К сожалению, такой подход не позволяет сторонним серверам проверять ключи клиентов, даже если они этого хотят. Вы можете обойти эту проблему, настроив официальный сервер аутентификации, который могут использовать сторонние игровые серверы, например, если клиент войдет на сервер аутентификации и получит случайный одноразовый токен, который он может использовать для входа в систему. игровой сервер (который затем передает токен серверу аутентификации для проверки).
В качестве альтернативы, вы можете выдавать действительные клиентские сертификаты или что-то вроде них своим клиентам. Вы можете использовать существующий протокол (например, TLS), который поддерживает аутентификацию сертификата клиента (рекомендуется), или реализовать свой собственный, например, так:
- Сертификат клиента состоит из произвольной строки идентификатора, пары открытого и секретного ключей и цифровой подписи идентификатора и открытого ключа с использованием мастер-ключа.
- Для входа клиент отправляет свой идентификатор, открытый ключ и подпись. Сервер отвечает уникальной строкой запроса (предпочтительно с идентификатором сервера и отметкой времени, которую клиент должен проверить), которую клиент подписывает закрытым ключом (чтобы доказать, что он знает ключ) и отправляет подпись на сервер.
- Сервер проверяет обе подписи, доказывая, что ID + открытый ключ образуют законный клиентский ключ (так как они были подписаны главным ключом) и что клиентский ключ фактически принадлежит клиенту (так как клиент мог подписать запрос сервера с частным ключ).
(Этот протокол может быть еще более упрощен, если клиент сгенерирует «запрос», состоящий из идентификатора сервера и метки времени, и подпишет его. Конечно, затем сервер должен проверить, что идентификатор и метка времени действительны. Также обратите внимание, что этот простой протокол сам по себе не помешает злоумышленнику-посреднику получить возможность перехватить сеанс клиента, хотя он не позволит им получить закрытый ключ клиента, необходимый для будущих входов в систему.)