Обеспечение безопасности REST API без изобретения велосипеда

Часто ли при разработке REST API сначала аутентифицируют пользователя?

Типичный пример использования, который я ищу:

  • Пользователь хочет получить данные. Конечно круто, мы любим делиться! Получите открытый ключ API и читайте дальше!
  • Пользователь хочет сохранить / обновить данные ... подождите! кто ты, ты можешь это сделать?

Я хотел бы создать его один раз и позволить, скажем, веб-приложению, приложению для Android или приложению для iPhone использовать его.

REST API кажется логичным выбором с такими требованиями

Чтобы проиллюстрировать свой вопрос, я воспользуюсь простым примером.

У меня есть элемент в базе данных с атрибутом рейтинг (целое число от 1 до 5).

Если я правильно понимаю REST, я бы реализовал запрос GET, используя язык по моему выбору, который возвращает csv, xml или json следующим образом:

http://example.com/product/getrating/{id}/

Скажем, мы выбираем JSON, который возвращаем:

{
  "id": "1",
  "name": "widget1",
  "attributes": { "rating": {"type":"int", "value":4} }
}

Это нормально для общедоступных API. Я понимаю эту роль.

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

Я попробую использовать другой пример с тем же предметом / рейтингом.

Если пользователь "JOE" хочет добавить оценку к элементу

Это можно сделать с помощью:

http://example.com/product/addrating/{id}/{givenRating}/

На этом этапе я хочу сохранить данные о том, что "JOE" дал продукту {id} рейтинг {givenRating}.

Вопрос: Откуда мне знать, что запрос пришел от «ДЖО», а не от «БОБ».

Кроме того, что, если бы это было для более разумных данных, таких как номер телефона пользователя?

На данный момент у меня есть:

1) Используйте встроенную функцию HTTP для аутентификации при каждом запросе, будь то простой HTTP или HTTPS.

Это означает, что теперь каждый запрос принимает форму:

https://joe:[email protected]/product/addrating/{id}/{givenRating}/

2) Используйте подход, подобный Amazon S3 с закрытым и открытым ключом: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3) В любом случае используйте cookie и сломайте часть REST без сохранения состояния.

Мне кажется, что второй подход лучше, но я задаюсь вопросом, действительно ли мне нужно заново изобретать все это? Сам хеширую, храню, генерирую ключи и т. Д.?

Это очень похоже на использование сеанса в типичном веб-приложении и самостоятельное переписывание всего стека, что обычно для меня означает «Вы делаете это неправильно», особенно когда речь идет о безопасности.

РЕДАКТИРОВАТЬ: Думаю, мне также следовало упомянуть OAuth.


person jfrobishow    schedule 30.08.2011    source источник
comment
Если вы отправляете имя пользователя и пароль с каждым запросом, используйте HTTPS.   -  person Matt Ball    schedule 30.08.2011
comment
Ничего общего с безопасностью, но RESTful API не будет использовать getrating и andrating; это будет просто rating, и вы должны GET, POST, PUT или DELETE к этому ресурсу.   -  person Duncan    schedule 31.01.2013


Ответы (3)


Редактировать 5 лет спустя

Используйте OAuth2!

Предыдущая версия

Нет, в использовании файлов cookie совершенно нет необходимости. Это не так безопасно, как HTTP Digest, OAuth или AWS от Amazon (которые несложно скопировать).

То, как вы должны смотреть на cookie, состоит в том, что это токен аутентификации в той же степени, что и Basic / Digest / OAuth / в зависимости от того, что было бы, но менее подходящим.

Однако я не считаю, что использование cookie противоречит принципам RESTful per se, если содержимое cookie сеанса не влияет на содержимое ресурса, который вы возвращаете с сервера.

Файлы cookie - это зло, прекратите их использовать.

person Evert    schedule 30.08.2011
comment
Я не считаю, что способ Amazon сложно скопировать ... как будто я не нахожу сложным писать JavaScript с нуля, но jQuery определенно помогает писать его хорошо. Прочитав об этом, я задумался, нет ли рамок, чтобы абстрагироваться от этого? - person jfrobishow; 30.08.2011
comment
Погугли это. Я написал реализацию для AWS, но я считаю, что она не полная: code.google.com/p/sabredav/source/browse/lib/Sabre/HTTP/ - person Evert; 30.08.2011
comment
Извините, но ответ неверный. Файлы cookie и HTTP-дайджест дополняют друг друга, но ортогональны - вы можете использовать второй для аутентификации пользователя и создания файла cookie. По сравнению с OAuth, безопасность на основе файлов cookie не будет работать, если у вас есть междоменные службы или если вы позволяете другим ненадежным людям писать клиента в вашу службу (задействованы третьи стороны) и хотите разрешить вашим пользователям отозвать доступ к приложению. Но в других случаях он работает точно так же, как OAuth, вы можете рассматривать файл cookie как токен доступа OAuth, который, кстати, вам тоже нужно где-то хранить. - person zihotki; 27.01.2015
comment
Мой ответ был написан до OAuth2, когда каждый токен OAuth представлял собой дайджест кучи информации, связанной с запросом. Это неверно для носителя OAuth2, который действительно в значительной степени соответствует токену в Cookie. - person Evert; 27.01.2015

Не беспокойтесь о том, чтобы быть "RESTful", беспокоитесь о безопасности. Вот как я это делаю:

Шаг 1. Пользователь попадает в службу аутентификации с учетными данными.

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

Шаг 3. Добавьте вызов точки входа в верхнюю часть каждого сценария веб-службы, который проверяет отпечаток пальца и идентификатор сеанса для каждого запроса веб-службы.

Шаг 4. Если отпечаток пальца и идентификатор сеанса недействительны или истекло время перенаправления на аутентификацию.

ПРОЧИТАЙТЕ ЭТО:

RESTful-аутентификация

person Daniel Pereira    schedule 30.08.2011
comment
Но тогда разве вы не заставляете пользователя входить в систему перед доступом к API каждый раз, когда истекает срок сеанса? Что вы делаете в случае мобильного устройства? Предоставить им постоянный ключ, чтобы им не приходилось входить в систему каждый раз, когда они используют приложение, использующее API? - person jfrobishow; 30.08.2011
comment
Я заставляю их войти в систему. Либо это, либо использование cookie, либо сопоставление отпечатка пальца с их UDID, но функция UDID означает, что пользователь должен получить доступ к службе с того же устройства. - person Daniel Pereira; 31.08.2011
comment
Что касается шага 3: это означает, что если я использую среду MVC, которая использует действия внутри контроллеров, я должен вводить в каждое действие два дополнительных параметра (отпечаток пальца и идентификатор сеанса)? - person sports; 25.09.2014
comment
@sports Что касается добавления функций в начале вызовов методов: если вы используете MVC / WebApi, перехватывайте действия с помощью OWIN. Если вы хотите разрешить что-либо через конечную точку, но вместо этого хотите защитить логику домена, используйте АОП, например PostSharp. Если вы используете свой собственный, просто используйте атрибуты и нарушите ряд принципов, чтобы добавить функциональность в атрибуты методов, которые вы хотите защитить. - person Suamere; 14.07.2015

Редактировать 3 года спустя

Я полностью согласен с Evert, использую OAuth2 с HTTPS и не изобретайте велосипед! :-)

С помощью более простых API-интерфейсов REST - не предназначенных для сторонних клиентов - также могут быть полезны веб-токены JSON.

Предыдущая версия

В любом случае используйте cookie и сломайте часть REST без сохранения состояния.

Не используйте сеансы, с сеансами ваша служба REST не будет хорошо масштабироваться ... Здесь есть 2 состояния: состояние приложения (или состояние клиента или сеанса) и состояние ресурса. Состояние приложения содержит данные сеанса и поддерживается клиентом REST. Состояние ресурса содержит свойства и отношения ресурсов и поддерживается службой REST. Вы можете очень легко решить, является ли конкретная переменная частью состояния приложения или состояния ресурса. Если объем данных увеличивается с увеличением количества активных сеансов, то он принадлежит состоянию приложения. Так, например, идентификация пользователя в текущем сеансе принадлежит состоянию приложения, а список пользователей или разрешений пользователей принадлежит состоянию ресурса.

Таким образом, клиент REST должен хранить факторы идентификации и отправлять их с каждым запросом. Не путайте REST-клиент с HTTP-клиентом. Они не одинаковы. Клиент REST также может быть на стороне сервера, если он использует curl, или он может создать, например, файл cookie только на стороне сервера, который он может совместно использовать со службой REST через CORS. Единственное, что имеет значение, служба REST должна аутентифицировать при каждом запросе, поэтому вы должны отправлять учетные данные (имя пользователя, пароль) с каждым запросом.

  • Если вы пишете клиент REST на стороне клиента, это можно сделать с помощью SSL + HTTP auth. В этом случае вы можете создать credentials -> (identity, permissions) кеш на сервере, чтобы ускорить аутентификацию. Имейте в виду, что если вы очистите этот кеш, и пользователи отправят один и тот же запрос, они получат такой же ответ, только это займет немного больше времени. Вы можете сравнить это с сессиями: если вы очистите хранилище сессий, пользователи получат status: 401 unauthorized ответ ...
  • Если вы пишете клиент REST на стороне сервера и отправляете факторы идентификации в службу REST через curl, у вас есть 2 варианта. Вы также можете использовать http auth или вы можете использовать диспетчер сеансов в своем клиенте REST, но не в службе REST.
  • Если кто-то ненадежный напишет ваш REST-клиент, вам нужно написать приложение для аутентификации пользователей и предоставить им возможность решать, хотят ли они предоставлять разрешения разным клиентам или нет. Oauth - уже существующее решение для этого. Oauth1 более безопасен, oauth2 менее безопасен, но проще, и я думаю, что есть несколько других решений этой проблемы ... Вам не нужно изобретать это заново. Существуют полные решения для аутентификации и авторизации с использованием oauth, например: сервер идентификации wso.

Файлы cookie не обязательно плохие. Вы можете использовать их в режиме RESTful, пока они не сохранят состояние клиента, а служба - только состояние ресурса. Например, вы можете сохранить корзину или предпочтительные настройки нумерации страниц в файлах cookie ...

person inf3rno    schedule 03.12.2013
comment
Как это не вдобавок к Don't worry about being "RESTful", worry about security. ответу? - person Dennis Braga; 19.02.2014
comment
Слишком поздно, и я не понимаю, о чем вы говорите, извините. : D Почитаю завтра этот пост, не помню по нему ... - person inf3rno; 20.02.2014
comment
Мне удалось еще раз прочитать пост. Yepp, я думаю, это потому, что мой пост задерживается на 2 года по сравнению с сообщением, которое вы упомянули. Вот и все, хорошего вечера! :-) - person inf3rno; 21.02.2014
comment
Просто пытаюсь понять больше. Что вы имеете в виду под сторонним клиентом? Чем для них небезопасен JWT? Спасибо. - person Yaobin Then; 15.11.2016