Можете ли вы помочь мне понять это? «Распространенные ошибки REST: сессии не имеют значения»

159

Отказ от ответственности: я новичок в школе мысли REST, и я пытаюсь обдумать это.

Итак, я читаю эту страницу, типичные ошибки REST , и обнаружил, что совершенно сбит с толку тем, что раздел о сессиях не имеет значения. Вот что говорит страница:

Клиенту не нужно «входить в систему» ​​или «устанавливать соединение». HTTP-аутентификация выполняется автоматически для каждого сообщения. Клиентские приложения являются потребителями ресурсов, а не услуг. Поэтому не к чему войти! Допустим, вы бронируете рейс через веб-сервис REST. Вы не создаете новое «сеансовое» соединение с сервисом. Скорее вы просите «объект создателя маршрута» создать для вас новый маршрут. Вы можете начать заполнять пробелы, но затем получить какой-то совершенно другой компонент в другом месте в Интернете, чтобы заполнить некоторые другие пробелы. Нет сеанса, поэтому нет проблемы переноса состояния сеанса между клиентами. Также нет проблемы "сессионной близости"

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

Было бы плохо иметь службу REST, скажем, /sessionкоторая принимает запрос GET, где вы передаете имя пользователя / пароль как часть запроса, и возвращает маркер сеанса, если аутентификация прошла успешно, это может быть прошло вместе с последующими запросами? Имеет ли это смысл с точки зрения REST, или это упущение?

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

Ответы:

79

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

Хорошо, я получаю, что HTTP-аутентификация выполняется автоматически для каждого сообщения - но как?

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

Было бы плохо иметь службу REST, скажем, / session, которая принимает запрос GET, в котором вы передаете имя пользователя / пароль как часть запроса, и возвращает маркер сеанса, если аутентификация прошла успешно, что могло бы затем будут переданы вместе с последующими запросами? Имеет ли это смысл с точки зрения REST, или это упущение?

Это не будет RESTful, поскольку оно несет состояние, но, тем не менее, оно довольно распространено, поскольку это удобно для пользователей; пользователь не должен входить каждый раз.

То, что вы описываете в «маркере сеанса», обычно называется cookie-файлом для входа . Например, если вы попытаетесь войти в свой Yahoo! В аккаунте есть флажок, который гласит "держи меня в сети в течение 2 недель". По сути, это означает, что (по вашим словам) «поддерживайте мой токен сессии в течение 2 недель, если я успешно войду в систему». Веб-браузеры будут отправлять такие файлы cookie для входа (и, возможно, другие) с каждым HTTP-запросом, который вы просите сделать для вас.

Z8000
источник
5
Этот ответ не имеет смысла для меня. Во-первых, в нем говорится, что разрешено передавать логин и пароль каждый раз, а значит и один раз, что имеет смысл. Затем предлагается вернуть клиенту состояние успешного входа в систему в виде токена. При необходимости токен может кодировать время создания. Нам, безусловно, разрешено возвращать информацию обратно клиенту. Так что это предложение мне кажется правильным. Ответ говорит, что это не хорошо, потому что «оно несет состояние», но разве идея «ST» в «REST» заключается в том, что состояние может передаваться между клиентом и сервером?
33

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

Грег Хьюгилл
источник
3
+1 Не могли бы вы уточнить: имеет ли ограниченное применение злоумышленник, который его перехватывает (поскольку он основан на текущем времени) ? Вы не говорите о cookie, который содержит зашифрованное имя пользователя и пароль? как так делает? (ИМХО)
Ройи Намир
2
@RoyiNamir: я не говорю о печенье. Сигнатура, используемая S3, является параметром для HTTP-запроса, но не является cookie, она пересчитывается для каждого запроса.
Грег Хьюгилл
Так что, если мне нужно сохранить некоторую информацию о пользователе, где бы я ее сохранить? в дБ? Я не хочу отправлять каждый запрос в БД .... и все же я хочу использовать отдых .... не могли бы вы помочь?
Ройи Намир
@RoyiNamir: Если у вас есть конкретные вопросы о том, как достичь какой-либо цели, пожалуйста, задайте новый вопрос . Я не могу ответить на дополнительные вопросы здесь, в комментариях.
Грег Хьюгилл
10

Многие люди не очень четко понимают принципы REST, использование токена сеанса не всегда означает, что вы сохраняете состояние, причина отправки имени пользователя / пароля с каждым запросом - только для аутентификации и для отправки токена (сгенерированного при входе в систему). просто), чтобы решить, есть ли у клиента разрешение запрашивать данные или нет, вы нарушаете правила REST, только когда вы используете имя пользователя / пароль или токены сеанса, чтобы решить, какие данные показывать! вместо этого вы должны использовать их только для проверки подлинности (чтобы показать данные или не показывать данные)

в вашем случае я говорю ДА, это RESTy, но старайтесь избегать использования нативных сессий php в вашем REST API и начинайте генерировать ваши собственные хешированные токены, срок действия которых истекает через определенный промежуток времени!

EvilThinker
источник
1
Спасибо. почему следует избегать нативной сессии php и использовать вместо нее собственные хеш-токены?
Мэтью
я говорю не о какой-то блестящей причине, просто для большей безопасности и большего контроля.
EvilThinker
Это лучше, чем принятый ответ. По крайней мере, он принимает предложение как RESTy, что имеет смысл. Однако я не понимаю, почему переданная информация не может использоваться для авторизации, зависящей от пользователя. Некоторые пользователи могут иметь доступ к некоторым данным, а другие нет. Это не делает протокол не RESTful.
8

Нет, дело не в этом. Google ClientLogin работает именно таким образом, за исключением того, что клиент получает указание перейти в «/ сеанс» с помощью ответа HTTP 401. Но это не создает сеанс, а только создает способ для клиентов (временно) аутентифицировать себя, не передавая учетные данные в открытом виде, и для сервера контролировать достоверность этих временных учетных данных, как он считает нужным.

mogsie
источник
11
@ unforgiven3 Пока возвращаемый токен используется только для аутентификации пользователя и не используется сервером для привязки пользователя к другому состоянию, хранящемуся на сервере, тогда я не вижу нарушений REST.
Даррел Миллер
4
@ unforgiven3 Возвращенный сервером токен, по сути, является доказательством того, что пользователь является тем, кем он себя считает. Таким образом, вместо каждого запроса, включающего имя пользователя и пароль, каждый запрос включает токен, который построен таким образом, что сервер может быть уверен в своей правдивости.
Даррел Миллер
1
@ unforgiven3, Даррел прав. Возвращенный токен должен отправляться клиентом при каждом HTTP-запросе, как при обычной дайджест-аутентификации, до истечения срока действия токена. Когда это происходит, клиент может повторить вход в систему, опционально запросив учетные данные пользователя или что-то еще. Я мог бы разработать ответ, если хотите. редактировать: (И спасибо за то, что не
отставали
1
Нет проблем, моги, всегда интересно обсуждать такие вещи :-) Я думаю, я вижу, куда вы, ребята, идете с этим, к сожалению, я просто недостаточно разбираюсь в дайджест-аутентификации, чтобы действительно понять это (в основном я просто не понимаю понять, как токен отсылается обратно при каждом HTTP-запросе, но это похоже на детали реализации). Однако теперь я понимаю, почему этот метод не нарушает принципы REST. Спасибо за ответы!
Роб
6
@ unforgiven3, это может помочь: токен является подписанным фрагментом информации. Так что это автономно. Сервер может проверить токен без проверки ранее сохраненного состояния. Так что это просто состояние, которое хранится на клиенте и передается туда и обратно.
Ираванчи
5

Хорошо, я получаю, что HTTP-аутентификация выполняется автоматически для каждого сообщения - но как?

«Авторизация:» HTTP-заголовок, отправленный клиентом. Либо основной (простой текст), либо дайджест.

Было бы плохо иметь службу REST, скажем, / session, которая принимает запрос GET, в котором вы передаете имя пользователя / пароль как часть запроса, и возвращает маркер сеанса, если аутентификация прошла успешно, что могло бы затем будут переданы вместе с последующими запросами? Имеет ли это смысл с точки зрения REST, или это упущение?

Вся идея сеанса состоит в том, чтобы создавать приложения с сохранением состояния, используя протокол без сохранения состояния (HTTP) и тупой клиент (веб-браузер), поддерживая состояние на стороне сервера. Один из принципов REST - «Каждый ресурс уникально адресуется с использованием универсального синтаксиса для использования в ссылках гипермедиа» . Переменные сеанса - это то, что не может быть доступно через URI. Поистине, приложение RESTful будет поддерживать состояние на стороне клиента, отправляя все необходимые переменные по HTTP, предпочтительно в URI.

Пример: поиск с нумерацией страниц. У вас будет URL в форме

http://server/search/urlencoded-search-terms/page_num

Это имеет много общего с закладками

Vartec
источник
4
Однако информация аутентификации недоступна через URI - все говорят об отправке информации аутентификации как части заголовка запроса. Чем это отличается от включения токена сеанса в запрос? Я не говорю использовать маркер сеанса в URI, но в данных, передаваемых в запросе.
Роб
Аутентификация устанавливает, разрешено ли вам выполнять это действие, и в приложении RESTful это не повлияет на его результат.
vartec
4
Токен сеанса также определяет, авторизованы ли вы для выполнения этого действия. Что вы имеете в виду, что это не повлияет на результат? Если вызывающий абонент не авторизован, он получает ошибку «Не авторизован». То же самое с токеном сессии. Я действительно не вижу разницы?
Роб
3
Нет, маркер сеанса - это дескриптор состояния, сохраненного на сервере. Это просто не RESTful. Что касается несанкционированного, я не вижу этого в результате. Я предпочел бы считать это исключением (как в try / catch).
vartec
Справедливо, vartec - это имеет смысл. Спасибо за продолжение!
Роб
3

Я думаю, что ваше предложение в порядке, если вы хотите контролировать время жизни клиентской сессии. Я думаю, что архитектура RESTful побуждает вас разрабатывать приложения без сохранения состояния. Как писал @ 2pence, «каждый HTTP-запрос должен содержать достаточно информации, чтобы получатель мог обработать его, чтобы он полностью соответствовал природе HTTP без сохранения состояния» .

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

LiorH
источник