Я не эксперт по безопасности, поэтому я ищу людей, чтобы пробить дыры в разработанной мной схеме аутентификации или указать на лучшую существующую схему, которая выполняет те же цели:
Обзор проблемы
У меня есть интерфейс, в котором клиент поддерживает жизненный цикл сеанса (это сеанс HTTP на веб-сервере, но это не имеет значения).
Сервер без сохранения состояния предоставляет некоторые службы, которые требуют аутентификации вызывающего абонента (сервер может выполнять эту аутентификацию).
Однако желательно, чтобы на сервере не требовалось аутентифицировать вызывающего абонента при каждом вызове, например, путем передачи учетных данных в каждом вызове. (Процесс аутентификации может быть дорогим.)
Также желательно не поддерживать состояние сеанса на сервере. С одной стороны, это просто требование хрупкого решения иметь независимые тайм-ауты сеанса как на клиенте, так и на сервере (от клиента нельзя избавиться), и тайм-аут сервера кажется необходимым для обеспечения надежного времени жизни сеанса на сервере (вместо того, чтобы полагаться на клиента, чтобы явно завершить сеанс в подходящее время). С другой стороны, сервер не настроен для хранения такого состояния.
На сервере есть явный метод authenticate
. Тогда возникает проблема: как сервер проверяет, что при вызове другого метода вызывающая сторона предварительно аутентифицировалась с использованием метода authenticate
, не сохраняя состояния сеанса на сервере?
Предлагаемое решение
Вот схема, которую я придумала:
Метод authenticate
принимает учетные данные в качестве входных параметров. После успешной аутентификации сервер возвращает две вещи:
- Отметка времени, указывающая время, когда была выполнена аутентификация.
- Зашифрованная версия кортежа {username, timestamp}, зашифрованная закрытым ключом
При последующих вызовах методов клиент передает оба этих значения обратно на сервер. Затем сервер расшифровывает зашифрованный кортеж {username, timestamp}. Если дешифрованная метка времени соответствует незашифрованному значению, которое также было отправлено клиентом, сервер знает, что клиент предварительно прошел аутентификацию (поскольку это единственный способ получить действительное зашифрованное значение). Расшифрованное имя пользователя сообщает серверу, какой пользователь прошел аутентификацию.
Срок действия зашифрованного ключа может быть установлен только путем разрешения временных отметок, которые находятся в пределах x часов текущего времени. Это не то же самое, что тайм-аут сеанса, но оно ограничивает окно, в котором злоумышленник может использовать скомпрометированную метку времени.
So
Боюсь, что эта схема наивна с дюжины способов. Какие слабости или плохую логику вы видите?