Служба HMAC и WCF .net

Так что я новичок в аутентификации HMAC, и я действительно не знаю, что делаю, и не читаю банкоматы.

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

Как реализовать аутентификацию HMAC в RESTful 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 или должен возвращать зашифрованное строка, которую я буду использовать позже для других транзакций (удаление, вставка услуг и т. д.)?

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

    }

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

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

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

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

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


person gdubs    schedule 27.11.2012    source источник


Ответы (2)


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

Если вы хотите получить хорошее представление о том, как работает служба RESTful и аутентификация, 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 для System.Web.Http.AuthorizeAttribute (не используйте атрибут авторизации Mvc). Попросите его перестроить подпись так же, как вы сделали это на стороне клиента, используя их секретный ключ, и если он не совпадает, вы можете вернуть 401. Затем вы можете украсить все контроллеры, требующие аутентификации, вашим новым атрибутом авторизации.

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

Ссылки:

Документация по Netflix Api: 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

Веб-API ASP.NET: http://www.asp.net/web-api

person Despertar    schedule 29.11.2012
comment
Спасибо за ответ! Это действительно немного прояснило ситуацию. Впрочем, у меня еще есть несколько вопросов. Поскольку я действительно новичок в этом и пробую это шаг за шагом, позвольте мне сначала начать с аутентификации входа в систему с помощью приложения iphone, которое вызывает веб-службу входа в систему. Я отправляю имя пользователя и хешированное слово. ), если это правда, я сохраняю имя пользователя и пароль (это будет мой общий ключ). Теперь, если я выполняю транзакцию получения после входа в систему, скажем, /GetAppointmentDetails?apptid=1.Как узнать, разрешено ли запрашивающей стороне увидеть подробности приложения? я передаю {имя пользователя} ..? - person gdubs; 30.11.2012
comment
вместе с ключом, чтобы проверить, является ли он нужным человеком и ему разрешено видеть детали встречи? Или мне hmac хешировать все параметры URL-адреса, полученные в /GetAppointmentDetails?hmac=kjsodjdkie...., и сравнивать этот токен/хэш-строку hmac с базой данных? Gahhh, действительно запутался. - person gdubs; 30.11.2012
comment
Итак, после прочтения netflix API у меня теперь есть идея получше. Но моя проблема заключается в части nonce, поэтому скажем, что я отправляю свое имя пользователя и pword, он возвращает true (с nonce?), я сохраняю pword для ключа, теперь я запрашиваю назначение транзакции, я отправлю обратно одноразовый номер, который я получил при входе в систему? и вернуть новый одноразовый номер с этим запросом, который будет использоваться в следующем. я все еще на правильном пути? - person gdubs; 30.11.2012
comment
Nonce означает «Число, использованное один раз». Таким образом, вы никогда не захотите отправлять один и тот же одноразовый номер дважды. На самом деле это может быть увеличенное число, случайные буквы/цифры, или я обычно предпочитаю использовать идентификаторы GUID, поскольку они спроектированы так, чтобы быть уникальными и простыми в создании, Guid.NewGuid.ToString(). На стороне сервера это может быть так же просто, как файл .txt с каждым использованным одноразовым номером, если вы уже используете базу данных, у вас может быть таблица, полная одноразовых номеров. Затем каждый раз, когда вы проверяете запрос, вы просто проверяете, что предоставленный им одноразовый номер еще не использовался, иначе это может быть кто-то, пытающийся воспроизвести предыдущее сообщение. - person Despertar; 30.11.2012
comment
Если вы не хотите подписывать каждый запрос меткой времени, одноразовым номером и хэшем hmac, а предпочитаете использовать подход с однократной аутентификацией, я бы предложил использовать аутентификацию с помощью форм. Первоначально это использовалось с оригинальными веб-формами asp.net, но на самом деле оно может работать достаточно хорошо во многих других сценариях. Как это работает, вы звоните в службу аутентификации и, если предоставлены правильные учетные данные, вы создаете зашифрованный токен аутентификации, который затем передается обратно в файле cookie. Теперь каждый раз, когда этот пользователь отправляет другой запрос, скажем, /GetAptDetails, этот токен также передается. - person Despertar; 30.11.2012
comment
И ASP.NET будет обрабатывать все детали аутентификации от вашего имени. Вы можете указать, как долго токен годен, и даже сохранить в нем имя пользователя, чтобы вы всегда могли идентифицировать пользователя с последующими запросами (возможно, разные пользователи будут иметь доступ к разным областям API в зависимости от групп или разрешений). msdn.microsoft.com/en-us/library/ff647070.aspx . Если вы не хотите использовать файлы cookie, должна быть также версия без файлов cookie, в которой вместо этого в строке запроса передается токен аутентификации. - person Despertar; 30.11.2012
comment
Хорошо, теперь это имеет смысл. Я пытался выяснить, как будет работать проверка одноразового номера, если он используется только один раз. Поэтому я сохраняю его в базе данных вместе с отметкой времени? Или лучше просто сравнить отметку времени при выполнении транзакции с текущей системная дата? Теперь возвращаясь к API Netflix, почему они требуют, чтобы вы предоставили Consumer_key, я предполагаю, что это просто еще один уровень безопасности для доступа к данным их клиента и не будет слишком актуальным для меня... Большое спасибо, это мне очень помогает. - person gdubs; 30.11.2012
comment
Consumer_key будет эквивалентом имени пользователя, за исключением того, что его не обязательно легко распознать. Каждому пользователю предоставляется один Consumer_key с Consumer_secret. Поскольку секрет никогда не отправляется в виде обычного текста и всегда хешируется вместе с другой информацией, вам нужно будет использовать пользовательский_ключ для поиска их копии пользовательских_секретов, чтобы они могли создать эквивалентный хэш hmac. Это позволяет вам не только знать, что они аутентифицированы, но, поскольку вы знаете, «кто» они, вы можете предоставить авторизацию для разных уровней вашего API. - person Despertar; 30.11.2012
comment
Хорошо знать! Спасибо за быстрый ответ. На всякий случай, не станет ли база данных слишком большой, особенно если каждая транзакция будет иметь одноразовый номер? Кроме того, если мобильное приложение будет отправлять запросы примерно 400–500 раз в день? Или мне следует очистить таблицу (одноразовый номер) через некоторое время? Также спасибо за ссылку на ваш проект Netflix! - person gdubs; 01.12.2012
comment
Если временная метка подходит только для, скажем, 10 минут, то технически вы можете очищать свои одноразовые номера каждые 10 минут, потому что, если кто-то попытается повторно использовать один из этих одноразовых номеров, срок действия временной метки истечет и сделает ее недействительной. - person Despertar; 01.12.2012
comment
Есть ли другой способ проверить запросы без использования одноразовых номеров? Немного беспокоюсь о снижении производительности, когда мне приходится проверять одноразовые номера и удалять их. Или мне вообще не стоит об этом беспокоиться? - person gdubs; 03.12.2012
comment
Без одноразового номера вы оставляете окно открытым на время, в течение которого действительна метка времени. Допустим, вы отправляете запрос на обновление ресурса. С одноразовым номером, если кто-то перехватит этот запрос и повторно отправит его, ему будет отказано в доступе, потому что одноразовый номер уже был использован. Без одноразового номера и, скажем, метки времени, которая подходит для 10 минут, кто-то может повторно отправить этот запрос в течение 10 минут до истечения срока действия метки времени, и подпись будет действительной. Вам решать, насколько важны данные, которые вы защищаете, и насколько плохо будет, если третья сторона сможет повторно отправить запрос. - person Despertar; 04.12.2012
comment
хорошо, так что я думаю, что я понимаю это сейчас. Nonce в основном генерируется клиентом, а затем отправляется в API, затем API проверяет, был ли уже запрошен одноразовый номер из базы данных, если нет, то все в порядке, а затем сохраняет, чтобы вести запись в течение следующих 10 минут. иначе возвращает ошибку . Правильно ли я понимаю? - person gdubs; 04.12.2012

Глядя на ваши вопросы в свою очередь

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

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

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

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

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

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

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

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

person joocer    schedule 29.11.2012