Я только начал разработку моего первого REST API в .NET. Поскольку он будет неактивен, я буду использовать токены для аутентификации:
Основная идея (System.Security.Cryptography):
- AES для шифрования + HMACSHA256 для целостности
- данные токена будут содержать объект со свойствами: имя пользователя, дату выдачи и тайм-аут
- будет храниться имя пользователя, хешированный пароль и хеш HMAC
Логин:
- проверьте правильность учетных данных (имя пользователя, сравнение хешированного пароля с значением db)
- если true, зашифровать объект данных
- использовать HMAC для сгенерированного токена и хранить его в базе данных
- вернуть токен (без HMAC) пользователю (cookie/string)
Запрос метода, требующего проверки подлинности:
- пользователь отправляет токен с каждым запросом
- расшифровывается токен
- если он истек, ошибка
- если не истек срок использования HMAC и сравнить имя пользователя + сгенерированный хеш с значениями db
- Если проверка db действительна, пользователь аутентифицирован
Как я вижу, этот подход имеет следующие преимущества:
- даже если db компрометируется, он не содержит фактического токена (хеш нельзя отменить...)
- даже если у злоумышленника есть токен, он не может увеличить срок действия, обновляя поля, так как дата истечения срока находится в самом маркере
Теперь, во-первых, мне интересно, действительно ли это хороший подход.
Кроме того, я до сих пор не понял, где хранить ключи AES и SHA256 на сервере (должен ли я просто жестко кодировать их? Если я помещаю их в web.config или использую машинный ключ, то у меня есть проблема в случае загрузки сбалансированные серверы,...).
И наконец, где я храню векторы AES IV, поскольку Crypto.CreateEncryptor требует его для дешифрования? Означает ли это, что пользователи должны отправлять токен + IV с каждым запросом?
Надеюсь, это имеет смысл, и я благодарю вас за ответы заранее.
UPDATE:
Хорошо, теперь я сделал еще несколько исследований и пришел с этим решением:
- токен будет содержать первоначально указанные данные (имя пользователя, дата выдачи и тайм-аут).
- сгенерирован с encrypt-then-mac (он включает в себя зашифрованные данные AES, вектор IV + тег этих двух значений для аутентификации, сгенерированный с помощью HMACSHA265)
- токен тега будет записан в db
- пользователь будет аутентифицирован, если:
- Тег
- действителен (аутентификация по токенам)
- данные могут быть дешифрованы
- токен еще не истек Тег
- соответствует тому, что написано в базе данных
- пользователь не заблокирован в базе данных (недействительность маркера по запросу)
- будут сохранены в отдельном разделе web.config. Эти же ключи должны быть на каждом сервере (для каждого приложения, конечно)
Я не использовал FormsAuthenticationTicket, потому что в .NET возникают следующие проблемы:
- одни и те же ключи используются для разных целей (машинные клавиши для состояний представления, ресурсы и формы).
- mac-then-encrypt, используемый .NET, не считается настолько безопасным, как encrypt-then-mac
- нет встроенного метода аннулировать токен до истечения срока его действия