HMAC и WCF Service.net


Итак, я очень новичок в аутентификации HMAC, и я действительно не знаю, что я делаю, ни читаю atm.

Я пытался правильно понять следующие статьи / ссылки / обсуждения:

Как реализовать аутентификацию HMAC в спокойном WCF API

Http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/22/how-to-implement-hmac-authentication-on-a-restful-wcf-service.aspx

Http://buchananweb.co.uk/security01.aspx

С учетом сказанного у меня есть несколько вопросов:

  1. Понимая первую ссылку, если, например, у меня есть служба loginAuthentication, созданная в .net и доступ к которой будет осуществляться из приложения iPhone, я передаю незашифрованное имя пользователя (сообщение) для этого и должен возвращает только true / false или должен возвращать зашифрованную строку, в которой я буду использовать позже для других транзакций (Delete, Insert services и т. д.)?

    [ServiceContract]
    
    public partial class LoginService
    {
    
     [OperationContract]
     bool Authenticate(string username) {
       // stuffs
     }
    

    }

  2. С учетом сказанного, после того, как я проверил пользователя, и это то, где я теряюсь. Может быть, мне лучше сохранить что-то в базе данных "с меткой времени" (кто-то мне об этом рассказывал, и я тоже читал некоторые дискуссии об этом)? Или я просто возвращаю его с зашифрованным сообщением (зависит от первого вопрос) так что каждый раз, когда делается запрос, метка времени уже прикреплена?

    A. И что мне делать с этой меткой времени?

    B. будет ли он использоваться после того, как сообщение будет отправлено снова для другой транзакции?

  3. Ключи и секретное сообщение. Насколько я понял, ключ будет паролем пользователя. Итак, если пользователь отправляет свое имя пользователя, я могу открыть сообщение, используя пароль этого пользователя? Это имеет смысл, если пользователь уже имеет сеанс и является просто запрос на получение данных или запрос на удаление, вставку и т. д. Должен ли он быть таким же, если он просто аутентифицирует имя пользователя и пароль пользователя?

Спасибо, что уделили мне время!

2 2

2 ответа:

Первое, что я хотел бы отметить, это то, что веб-Api WCF был бета-проектом, который больше не разрабатывается. Он был заменен на ASP.NET Web API, который является удивительным фреймворком для разработки RESTful services.

Если вы хотите получить хорошее представление о том, как работает RESTful service и аутентификация, API Netflix будет отличным местом для начала. У них есть много документации, касающейся части безопасности, и это помогло мне понять HMAC намного больше.

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

Подпись создается путем объединения

1. Timestamp (unix epoc is the easiest to send in urls)
2. Nonce (a random number that can never be used twice to protect against someone re-using it)
3. Message (for a GET request this would be the URL, a POST would be the whole body)
4. Signature (the three previous items combined and hashed using the secret key)

Каждый из вышеперечисленных элементов может быть отправлен в строке запроса запрос, то сервер может использовать первые 3 и их копии секретного ключа для воссоздания подписи. Если подписи совпадают, то все хорошо.

В RESTful API, который находится над обычным HTTP (не используя HTTPS над ssl), я бы подписывал каждый отправленный запрос, потому что это снова аутентифицирует и обеспечивает целостность сообщения. В противном случае, если вы просто отправляете маркер аутентификации, вы знаете, что пользователь аутентифицирован, но как вы узнаете, что сообщение не было подделано, если у вас нет сообщения Дайджест (хэш HMAC) для сравнения?

Простой способ реализовать проверку подписи на стороне сервера-это переопределить OnAuthorization для системы.Сеть.Http.AuthorizeAttribute (убедитесь, что не используется атрибут MVC autorize). Попросите его перестроить подпись так же, как вы сделали это на стороне клиента, используя их секретный ключ, и если он не соответствует, вы можете вернуть 401. Затем вы можете украсить все контроллеры, требующие аутентификации, новым атрибутом authorize.

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

Литература:

Netflix Api Docs: http://developer.netflix.com/docs/Security#0_18325 (переходите к части о создании подписей, у них также есть ссылка, которая показывает полный пример .NET для создания подписи HMAC)

Класс .NET для создания сигнатур HMAC http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs

Netflix API Wrapper я написал: https://bitbucket.org/despertar1318/netflix-api/overview

ASP.NET Web API: http://www.asp.net/web-api

Рассматривая ваши вопросы по очереди

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

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

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

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

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

Именно здесь происходит HMACing. У вас есть общий секрет, у вас есть сообщение, Вот как я обычно объединяю все это вместе.

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

Наконец убедитесь, что сообщение содержит метку времени (желательно UTC), таким образом вы можете предотвратить повторное воспроизведение сообщения позже. Служба, которая отвечает на сообщение, может сравнить отметку времени с тем, что она считает временем. Если он выходит за заданные границы, сообщение не будет выполнено. Поскольку метка времени будет частью HMAC, кто-то не может просто обновить дату и воспроизвести сообщение, хэши не будут совпадать, как только сообщение будет изменено.