Аутентификация маркера REST API

Я только начал разработку моего первого 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 возникают следующие проблемы:

Ответ 1

Это продолжение из потока комментариев в вопросе.

Кажется, вы немного смущены тем, что именно, OAuth, так что, надеюсь, я смогу прояснить это здесь.

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

Как правило, вы заинтересованы в реализации OAuth с точки зрения сайта (например, AcmeWidgets.com), чтобы пользователь мог войти в систему через Facebook или Google или что-то в этом роде. Тем не менее, вы также можете реализовать сторону обслуживания (например, где обычно будет Facebook) и разрешить другим пользователям аутентифицироваться против ВАС.

Итак, скажем, у вас есть веб-сервис, позволяющий сторонним сайтам предоставлять виджеты Acme-брендов для пользователей. Ваш первый сторонний разработчик - популярный MyBook.org. Поток будет выглядеть примерно так:

  • Кто-то приглашает пользователя использовать приложение "Acme Widgets" в своем профиле MyBook.
  • Пользователь нажимает кнопку, которая перенаправляется на AcmeWidgets.com. URL-адрес выглядит примерно так:

    http://acmewidgets.com/oauth/user?r=http%3A%2F%2Fmybook.org%2Foauth%2Fclient&appid=12345

  • Пользователь спрашивает, хотят ли они разрешить MyBook получать доступ к своим данным и виджетам.
  • Пользователь нажимает "Да", после чего Acme Widgets отмечает, что пользователь разрешил его.
  • Пользователь перенаправляется обратно в MyBook по адресу, подобному этому:

    http://mybook.org/oauth/client?token=ABCDEFG

  • MyBook, на стороне сервера, теперь берет этот токен и помещает вызов веб-службы BACK в AcmeWidgets:

    http://acmewidgets.com/oauth/validate?token=ABCDEFG&appid=12345&appsecret=67890

  • AcmeWidgets отвечает конечным маркером идентификации, идентифицирующим пользователя.
  • В противном случае он терпит неудачу, что означает, что пользователь пытается подделать токен, или они отказали в разрешении или в каком-либо другом случае отказа.
  • MyBook с маркером теперь может вызывать API-интерфейсы AcmeWidgets:

    http://acmewidgets.com/api/provision?appid=12345&token=ABC123&type=etc

Это все известно как танец OAuth. Обратите внимание, что здесь существует ряд определенных функций реализации, таких как URL-адреса, способы кодирования различных токенов, могут ли токены истекать или отменяться и т.д.

Надеюсь, это очистит все для вас!