Безопасность: Насколько уязвима эта схема аутентификации / шифрования?

У меня есть игра клиент-сервер, где клиент подключается к серверу и остается подключенным во время игры (около 5-60 минут).

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

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

Поскольку я все равно хочу сохранить отдельный сервер входа в систему, моя идея такая:

  1. Клиент отправляет HTTPS-запрос на сервер входа с учетными данными (или регистрационной информацией)
  2. Сервер входа в систему собирает информацию о пользователе и генерирует временный ключ шифрования сеанса RC4.
  3. Информация о пользователе + сеанс RC4 + временная метка + дайджест (я могу рассчитывать на синхронизацию обоих серверов по времени) с секретным симметричным ключом, совместно используемым игровым сервером и сервером входа в систему.
  4. Упакованные данные + ключ шифрования сеанса RC4 + IP-адрес игровому серверу отправляются в качестве ответа на запрос HTTPS клиенту.
  5. Клиент открывает соединение с игровым сервером, отправляет начальное незашифрованное приветственное сообщение с зашифрованной информацией о пользователе в качестве полезной нагрузки.
  6. Игровой сервер распаковывает данные, упакованные в (3). Теперь он знает пользователя и ключ шифрования RC4, который предполагается использовать.
  7. Если временная метка указывает, что срок действия учетных данных для входа истек, клиенту возвращается ошибка (который затем должен получить новую информацию). Если расшифрованные данные пользователя не могут быть проверены с помощью дайджеста, возвращается другая ошибка.
  8. Если все проходит нормально, сервер отправляет незашифрованный LOGIN_OK, и начинается зашифрованный обмен данными RC4.

Возможные проблемы безопасности:

  • Игровой сервер на 100% доверяет расшифрованной им информации о пользователе. Это делает серверы полностью разделенными, что приятно, но если ключ будет скомпрометирован, пользователи могут полностью подделать свою информацию о пользователе. Это можно было бы несколько смягчить, повернув эти клавиши так, чтобы каждый день или месяц появлялся новый ключ. И игровой сервер, и сервер входа в систему могут получить это от третьего сервера, который управляет их ключами. Это может быть излишним, поскольку: а) в случае взлома, когда исходный код открыт на серверах, они могут быть перезапущены с новым ключом б) достаточно хороший ключ + шифрование должно усложнять атаки методом грубой силы (предложения по алгоритму ?)

  • RC4 - не самый безопасный алгоритм, но я обязательно выбрасываю первые 512 байтов или около того, и каждый ключ действителен только в течение ограниченного времени, например 24ч.

  • Из того, что я вижу, не кажется уязвимым для посредников: SSL защищает сеансовый ключ RC4, в (5) сеансовый ключ RC4, отправляемый на игровой сервер, также зашифрован. Все, что возможно, - это DoS и заставить пользователя снова запросить ключ. Если данные в (2) кэшируются до истечения срока их действия, это не должно создавать новый пакет.

  • Шифрование в (3) можно улучшить, добавив к ключу случайные биты. Эти случайные биты отправляются вместе с зашифрованным пакетом и представляются игровому серверу в (5). В (6) игровой сервер добавляет эти случайные биты к своему ключу и использует результат для расшифровки данных. Таким образом, злоумышленник не сможет увидеть изменения упакованных данных.

Есть ли какие-то уязвимости, которые я здесь не замечаю?

Сводка созданных полезных нагрузок:

  • Учетные данные клиента (защищенные SSL), отправленные на сервер входа
  • Информация о пользователе + временная метка + временный ключ сеанса игрового сервера + дайджест, зашифрованный сервером входа с использованием секретного ключа, совместно используемого с игровым сервером, передается клиенту, который - без его изменения - передает его на игровой сервер. Должен быть устойчивым, потому что: a) клиент не знает секретный ключ; b) имеет метку времени, чтобы избежать повторной отправки тех же данных; c) дайджест для проверки правильности шифрования содержимого
  • временный ключ сеанса игрового сервера, отправляемый сервером входа в систему клиенту вместе с зашифрованными данными. Защищено SSL.
  • Пакет для входа на сервер клиентской игры, состоит из зашифрованного пакета, полученного сервером входа в систему.

Сводка ключей шифрования:

  • Временный ключ сеанса игрового сервера: генерируется случайным образом сервером входа в систему для зашифрованной связи игрового сервера ‹-> с клиентом. Генерируется сервером входа в систему, передается клиенту и игровому серверу.
  • Ключ шифрования секретной информации о пользователе. Распространяется между игровым сервером и сервером входа, используется для передачи информации о пользователе на игровой сервер с клиентом в качестве мессенджера. У клиента нет этого ключа.

person Nuoji    schedule 16.02.2011    source источник


Ответы (5)


Во-первых, я бы не стал использовать RC4. Существуют как более быстрые, так и более безопасные потоковые шифры, поэтому, если вы контролируете и клиент, и сервер, вы, вероятно, сможете добиться большего, чем RC4. Отброса только 512 байтов может быть недостаточно для атаки Флурера, Мантина и Шамира, но даже если вы отбросите больше байтов, есть еще атака Кляйна и т. Д. Я не знаю, стоит ли это того.

Во-вторых, убедитесь, что генерируемые вами ключи случайны. Я знаю, что это кажется очевидным, но для примера см .: http://www.debian.org/security/2008/dsa-1571

Но настоящая проблема заключается в следующем: «Игровой сервер на 100% доверяет расшифрованной им информации о пользователе. Это делает серверы полностью разъединенными, что хорошо, но если ключ будет скомпрометирован, пользователи могут полностью подделать свою информацию о пользователе».

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

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

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

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

person Zed    schedule 16.02.2011
comment
Вы должны предположить, что пользователь знает ключ. Его игровой клиент должен знать ключ, чтобы общаться с сервером. Уммм, клиент передает только зашифрованную информацию о пользователе от логина на игровой сервер. Поскольку клиент никогда не расшифровывает его, у клиента нет ключа. Клиенту выдается сеансовый ключ для зашифрованной связи с игровым сервером, но это совсем другой ключ. - person Nuoji; 16.02.2011
comment
Для генерации ключей на Java (и в этом случае и игровой сервер, и сервер входа в систему находятся на java) я обычно использую SecureRandom и, в частности, SHA1PRNG. Достаточно хорошо? - person Nuoji; 16.02.2011
comment
Что бы вы посоветовали в качестве альтернативы RC4? - person Nuoji; 17.02.2011

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

person Nick Johnson    schedule 17.02.2011
comment
Предполагается, что игровой сервер сможет обрабатывать большое количество одновременных игроков. С серверами на Java я использую неблокирующие сокеты. К сожалению, это означает реализацию SSL поверх стандартных сокетов. В процессе этого я обнаружил, что для каждого соединения потребуется выделить около 32 КБ из-за того, как механизм SSL реализован в java. Незашифрованная версия будет использовать менее 100 байт. Это требование к памяти + тот факт, что реализация Java SSL действительно плохо подходит для неблокирующего ввода-вывода, заставили меня искать другие решения. - person Nuoji; 18.02.2011
comment
@Nuoji Подождите, Java не поддерживает SSL через асинхронные сокеты? Даже если это так, я был бы поражен, если бы никто не занялся этим раньше. Что касается аргумента о накладных расходах, вам необходимо определиться с моделью угроз и определить, что для вас важнее - накладные расходы на сервер или безопасность. - person Nick Johnson; 19.02.2011
comment
Нет, здесь нет встроенного асинхронного SSL. Конечно, он был реализован, и я тоже сделал это сам. Думаю, дело в масштабе. Все обстоит немного иначе, когда вы проектируете более 5000 одновременных подключений. - person Nuoji; 19.02.2011
comment
@Nuoji Как я уже сказал, вам нужно подумать о своей модели угроз. Если вы заботитесь о безопасности, вам необходимо использовать SSL, независимо от дополнительных накладных расходов. - person Nick Johnson; 20.02.2011
comment
Я сомневаюсь, что у меня было бы Агентство национальной безопасности или подобное, пытающееся взломать его. Впрочем, весьма вероятен очень умный и целеустремленный читер. Если для взлома сообщений требуется достаточно времени (скажем, неделя), все в порядке. - person Nuoji; 20.02.2011
comment
@Nuoji Вам не нужно АНБ - вам просто нужен один решительный злоумышленник, который затем упаковывает эксплойт для использования всеми остальными. И это не вопрос времени, чтобы взломать единичное сообщение, это вопрос уязвимостей протокола. - person Nick Johnson; 21.02.2011
comment
Собственно, вопрос в том, есть в протоколе эксплойт или нет. Даже если я использую SSL, мне придется разработать какой-то протокол, поскольку серверы входа и игровые серверы разделены. Мне все равно нужно, чтобы клиент получил какой-то токен для представления игровому серверу. Что меня интересует, так это знать, в чем заключаются слабые стороны предложенного мной протокола, и можно ли его использовать. - person Nuoji; 21.02.2011
comment
@Nuoji Попросите сервер входа в систему выдать клиенту сертификат SSL. Нет необходимости изобретать собственный протокол - просто посмотрите на количество уязвимостей, обнаруженных в реализациях SSL, чтобы понять, насколько легко ошибиться. - person Nick Johnson; 21.02.2011
comment
Думаю, я не внимательно прочитал ваш исходный ответ: - /. Это сработает. К сожалению, я придерживаюсь требований к памяти SSL. По-прежнему существует проблема с требованиями к памяти. для SSL, и мне также может потребоваться детальный контроль над тем, какое шифрование использует SSL, но последнее, надеюсь, можно контролировать. Мне также нужно сохранить другие части моего протокола, такие как зашифрованная полезная нагрузка, которую клиент отправляет на сервер, поскольку содержимое должно храниться в секрете от пользователя. На практике это заменит только RC4 на то, что предлагает SSL для шифрования. - person Nuoji; 21.02.2011

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

С первого взгляда протокол кажется нормальным. Также нет атаки повторного воспроизведения, поскольку вам действительно нужен симметричный сеансовый ключ, чтобы делать что-либо значимое. Лучшее, что вы можете сделать, - это переключиться на AES, это тоже очень быстро и безопасно. Я очень сомневаюсь, что вы заметите снижение производительности при переходе на AES.

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

person user220201    schedule 17.02.2011
comment
Интересно, должно ли шифрование быть таким хорошим? Я использую шифрование по двум причинам: 1) Он аутентифицирует игрока на игровом сервере - показывая игровому серверу, что он знает, как зашифровать данные, он подтверждает, что он получил действительный сеансовый ключ от сервера входа в систему. 2) Он предотвращает случайное подслушивание, которое позволит злоумышленнику увидеть игровой процесс оппонента. Количество пакетов между игровым сервером и игроком обычно невелико (менее 1000 пакетов на игровой сеанс, один игровой сеанс в день), и в любом случае информация быстро становится бесполезной в течение нескольких дней. Может ли RC4 все еще быть приемлемым? - person Nuoji; 18.02.2011
comment
@Nuoiji - Конечно, хорошо, я куплю этот аргумент. Таким образом, шифрование RC4 фактически сообщает вам только о том, что пользователь аутентифицирован, и в дополнение к этому вы получаете защиту от случайных перехватчиков и случайных злоумышленников. Мое единственное предложение: завтра, если игра станет популярной, и вы введете в нее какую-то валюту и коммерцию, может стать более привлекательным быть злоумышленником, и в этот момент вы, возможно, захотите усилить шифрование, верно? Если да, то зачем вообще возиться с RC4, если он не дает улучшения производительности? Я понимаю, если вы тоже пойдете с RC4. - person user220201; 18.02.2011
comment
Есть два других приятных свойства RC4: 1) Он работает с меньшими ключами, что полезно, если я попытаюсь избежать процедуры CCATS Commodity Classification для клиента, используя ключ длиной 64 бита или меньше. 2) Это потоковый шифр, который очень удобно кодировать, когда протокол в любом случае обычно работает с потоком. - person Nuoji; 20.02.2011

В итоге я также разместил сообщение на sci.crypt и постараюсь обобщить предлагаемые изменения (насколько я их понимаю) ниже, если это может быть интересно.

Шаг 1. Клиент отправляет HTTPS-запрос на сервер входа с учетными данными

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

Шаг 3. Информация о пользователе + сеанс RC4 + временная метка + дайджест

Используйте алгоритм шифрования, обеспечивающий целостность, вместо явного использования дайджеста. Например. AES-GCM или AES-CCM. Добавьте дополнительное поле идентификатора на шаге 1. Также добавьте ip к игровому серверу.

Шаг 4. Упакованные данные + ключ шифрования сеанса RC4 + IP-адрес игровому серверу отправляются в качестве ответа.

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

Шаг 5. Клиент открывает соединение с игровым сервером, отправляет начальное незашифрованное приветственное сообщение с зашифрованной информацией о пользователе в качестве полезной нагрузки.

Добавьте к полезной нагрузке самоназначенный идентификатор на шаге 1 в незашифрованном виде.

Шаг 6: игровой сервер распаковывает данные, упакованные в (3). Теперь он знает пользователя и ключ шифрования RC4, который предполагается использовать.

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

Шаг 8. Если все проходит нормально, сервер отправляет незашифрованный LOGIN_OK, и начинается зашифрованный обмен данными RC4.

На этом этапе игровой сервер не может быть уверен в личности клиента. Используйте ключ сеанса и зашифруйте одноразовый номер + строго увеличивающийся идентификатор сеанса + состояние успешного входа в систему с помощью AES-GCM / CCM и отправьте его клиенту.

Клиент расшифровывает и проверяет состояние успешного входа в систему. Если это правда, то клиент знает, что игровой сервер знает ключ сеанса (GCM / CCM проверяет, что пакет не был подделан). Клиент возвращает sid + nonce.

Сервер проверяет, что sid + nonce совпадают с отправленными значениями.

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

Что касается RC4

В RC4 есть уязвимости, но для данной схемы этого, вероятно, будет достаточно из-за довольно агрессивного перепланирования ключей. Однако есть современные шифры, которые более безопасны и быстрее, например Snow 2.0 или Trivium.

person Nuoji    schedule 25.02.2011

Просто используйте SSL для игрового сервера. Современный криптоанализ привел к нескольким очень быстрым реализациям некоторых из лучших алгоритмов шифрования. Например, хорошо оптимизированные реализации AES могут легко зашифровать со скоростью лучше 150 МБ / с на любой удаленной современной машине. Кроме того, хотя AES пользуется большим уважением, у него есть два недостатка, о которых я знаю, но при правильном использовании эти недостатки становятся несущественными.

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

person Lunatic Experimentalist    schedule 17.02.2011
comment
Интересный. О каких двух слабостях AES вы говорите? - person user220201; 17.02.2011
comment
См. Мой ответ Нику Джонсону о том, почему я не хочу использовать SSL для игрового сервера. Не могли бы вы пояснить свой отрывок относительно алгоритма планирования ключей? - person Nuoji; 18.02.2011
comment
@ user220201 AES имеет связанную слабость ключа, но это не имеет значения, если вы выполняете правильный вывод ключа и то, что называется атакой по времени кэширования, но для этого требуется, чтобы перехватчик мог выполнить код на машине, выполняющей шифрование / дешифрование. - person Lunatic Experimentalist; 20.02.2011
comment
@Nuoji В части планирования ключей я имел в виду, что вам необходимо периодически менять ключи шифрования и аутентификации таким образом, чтобы злоумышленнику было трудно предугадать это. Не существует идеального способа сделать это, но одни способы будут лучше других. - person Lunatic Experimentalist; 20.02.2011
comment
Как видно из описания, сервер входа в систему создает ключ сеанса. Этот ключ может быть действителен в течение 1 минуты или 24 часов - я не знаю, какой разумный срок. В любом случае сеансовый ключ будет сгенерирован из достаточно безопасного псевдослучайного кода. Не должно быть никакой корреляции между двумя разными сеансовыми ключами, сгенерированными для одного и того же пользователя в разное время. - person Nuoji; 20.02.2011
comment
@Nuouji Я на самом деле рекомендовал использовать безопасный алгоритм хеширования для создания нескольких ключей шифрования и аутентификации из одного сеансового ключа, поскольку создание сеансового ключа может занять довольно много времени, а не то, что вы хотели бы делать с высокой частотой в потенциально чувствительном ко времени приложении . - person Lunatic Experimentalist; 22.02.2011