Подтвердить что ты не робот

Аутентификация клиента на сервер в С++ с использованием сокетов

Я использую систему входа/аутентификации для моей маленькой сервер-клиентской программы. Мне интересно, как это сделать, и я надеялся получить некоторые полезные советы от Stack Overflow, как всегда. Вот как я себе представляю, что я это сделаю.

  • Клиент подключается к серверу.
  • Сервер отправляет клиенту "токен" (в зависимости от времени и т.д.)
  • Клиент возвращает имя пользователя и зашифрованный пароль sha1 вместе с токеном.
  • Сервер получает их и аутентифицирует пользователя для учетных данных в серверной базе данных.
  • Теперь токен проверяется и пользователь подписывается с токеном.

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

Детали реализации не требуются, так как я способен выполнять реализацию.

Мой вопрос, скорее, был бы двумя вопросами:

  • Какие существуют способы достижения системы входа/аутентификации с сокетами.
  • Какие способы защиты моего соединения "клиент-сервер"
  • EDIT. Я забыл спросить, так как это вопрос на С++, есть ли библиотеки, которые могут помочь в шифровании/аутентификации?

Безопасность - это проблема для меня, поэтому я хочу быть уверенным, что я прав.

Возможно, некоторая справочная информация. Это игровой сервер, человек входит в свою учетную запись и отправляется в "Лобби", где он может выбрать "Мировой сервер" для игры. Мировой сервер - это отдельный процесс, выполняемый (возможно) на другом компьютере в той же сети.

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

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

С уважением, Джесси

4b9b3361

Ответ 1

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

  • Клиент подключается к серверу, отправляя имя пользователя (но не пароль)
  • Сервер отвечает путем отправки уникального случайного числа
  • Клиент шифрует это случайное число, используя хэш своего пароля в качестве ключа
  • Клиент отправляет зашифрованное случайное число на сервер
  • Сервер шифрует случайное число с правильным хешем пароля пользователя
  • Сервер сравнивает два зашифрованных случайных числа

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

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

Библиотеки: Beecrypt и OpenSSL это пара очевидных. Если у вас нет достаточно конкретной причины, чтобы сделать иначе, TLS - это то, что вы, вероятно, хотите использовать (это немного больше, чем то, что я изложил выше, включая двухстороннюю аутентификацию, поэтому не только сервер знает, кто клиент но клиент также знает, кто такой сервер, поэтому он обоснованно проверял, что он не связан с кем-то еще, кто мог бы просто забрать его номер кредитной карты и запустить с ним).

Edit:

Чтобы проверить подлинность каждого пакета без накладных расходов на шифрование всего, вы можете сделать что-то вроде этого:

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

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

Чтобы минимизировать накладные расходы, вы можете отправить только часть результата с каждым пакетом - например, если вы используете AES в режиме счетчика, он будет генерировать 16 байт результата для каждого зашифрованного вами номера. Включите только (скажем) два байта из них с каждым пакетом, поэтому вам нужно только зашифровать число раз каждые 8 ​​пакетов. Теоретически это снижает безопасность - злоумышленник может просто попробовать все 65536 возможных значений для пакета, но если вы предполагаете, что соединение было скомпрометировано после (скажем) двух плохих попыток, вероятность того, что злоумышленник получит правильное значение, станет довольно маленьким (и, конечно же, вы можете в значительной степени выбрать шансы, с которыми вы готовы жить, контролируя количество неудачных попыток, которые вы разрешаете, и размер проверки подлинности, который вы включаете в каждый пакет).

Ответ 2

Если безопасность важна для вас, не сворачивайте ее самостоятельно. Вам нужна защищенная библиотека сокетов. Что-то вроде OpenSSL.