Выйти: ПОЛУЧИТЬ или ПОСТИТЬ?

435

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

Как прагматик, я склонен использовать GET, потому что реализовать его намного проще, чем POST; просто оставьте простую ссылку, и все готово. Это, кажется, имеет место с подавляющим большинством веб-сайтов, о которых я могу думать, по крайней мере, из головы. Даже Stack Overflow обрабатывает выход с помощью GET.

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

Все, что я прочитал до сих пор, говорит о том, что POST следует использовать для «разрушительных действий», тогда как действия, которые не изменяют внутреннее состояние запросов, подобных запросам и тому подобное, должны обрабатываться с помощью GET . Исходя из этого, реальный вопрос здесь:

Считается ли выход из приложения разрушительным действием или он изменяет внутреннее состояние приложения?

Даниэль Лиуцци
источник
Что ж, если вы посещаете сайт в первый раз, а ссылка для выхода отсутствует, вы выйдете из системы при входе в систему. Это было бы хорошо после того, как вы вошли во второй раз, так как URL выхода уже кэширован. Но можно предположить, что любой приличный ускоритель сможет отфильтровать большинство выходных URL.
HyperCas
2
HyperCas, ускорители, отфильтровывающие URL для выхода из системы, была теорией, которую я рассматривал, и одной из причин, по которой я решил опубликовать вопрос. Я чувствую небольшое нежелание просто доверять логике ускорителя, и однажды пользователь с дерьмовым ускорителем пожаловался, что не может войти в систему. Знаете ли вы, соответствуют ли они стандарту или такой стандарт существует?
Даниэль Лиуцци
Любой ускоритель, который автоматически отправил форму (например), был бы вредоносным ПО IMO ... совершенно нелогично думать, что ускоритель отправит форму автоматически. Представьте, что вы посещаете Google. Как можно отправить форму поиска? Никто не может объяснить вредоносное ПО, так как оно слишком непредсказуемо и не следует правилам.
Алекс
3
@AlexW - Я думаю, вы не поняли мой вопрос. Сценарий ускорителя, который я предложил, состоит в том, чтобы показать возможную проблему при использовании GET, а не POST, поэтому не будет никакой формы для публикации, только простые ссылки, за которыми у ускорителей не возникнет никаких проблем.
Даниэль Лиуцци
1
Я понимаю, что слишком поздно для этого, но Алекс, это не то, о чем спрашивает Дэниел. Он говорит, что если пользователь щелкнет ссылку выхода из системы, а акселератор вернет страницу кэшированного выхода без попадания в приложение, то пользователь останется в системе. Ничего общего с вредоносным ПО, хотя проверка FYI на строке User-Agent не исправит все равно что угодно.
Роб Грант

Ответы:

476

Использование POST.

В 2010 году использование GETбыло, вероятно, приемлемым ответом. Но сегодня (в 2013 году) браузеры будут предварительно выбирать страницы, которые, по их мнению, вы посетите в следующий раз.

Вот один из разработчиков StackOverflow, который говорит об этой проблеме в твиттере:

Я хотел бы поблагодарить мой банк за выход из GET-запроса и команду Chrome за удобную предварительную выборку URL-адресов. Ник Крейвер ( @Nick_Craver ) 29 января 2013 г.

Интересный факт: StackOverflow используется для обработки выхода через GET, но не больше.

Дэвид Мердок
источник
2
Спасибо за это обновление, Дэйв. Я даже не заметил, что SO переключил их журнал на POST, и я, честно говоря, не догадывался, что Chrome поставляется со встроенной функцией предварительной выборки. Наконец, цитируемый вами трюк никогда бы не стал лучшим примером проблемы, описанной мной мой вопрос и подтверждает мои подозрения. Я голосую за ваш ответ и делаю его принятым.
Даниэль Лиуцци
4
В моем браузере, Stackoverflow выход из системы выглядит как <li> <a href="https://stackoverflow.com/users/logout"> выйти </a> </ li> который является GET, не POST
boatcoder
9
@ Mark0978, нажмите на ссылку.
Дэвид Мердок
2
Интересно. Вероятно, это одна из моих наименее любимых функций, выход из системы, который затем спрашивает меня, уверен ли я. Думаю, это предотвращает выход из предварительной загрузки, но Amazon, Ebay и Gmail все используют GET для выхода из системы без этой хитрости между тем, что пользователю сообщается, выходом из системы и фактическим событием выхода из системы. Я полагаю, что в промежутке между страницами многие люди ошибочно полагают, что они вышли из системы. Проблемы с этим на SO минимальны, без денег, и 99% всего в любом случае публично.
кодек
7
@Red Согласно стандарту HTTP / 1.1, это ошибка сервера, а не браузера. Ожидается, что GET не будет иметь побочных эффектов на стороне сервера. В стандарте даже говорится, что «пользователь не запрашивал побочные эффекты, поэтому не может нести за них ответственность».
eyuelt
45

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

Вы действительно спрашиваете, должен ли браузер продолжать посылать аутентификационную информацию при каждом запросе.

Возможно, если ваше приложение создает иллюзию входа в систему, то вы должны иметь возможность «выйти», используя javascript. Не требуется поездка туда и обратно.


Филдинг Диссертация - раздел 5.1.3

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

Даррел Миллер
источник
1
Я на самом деле не знал об этом. Тогда я думаю, что мое приложение не будет очень RESTful вообще, так как я использую ASP.NET MVC с FormsAuthentication, и оно опирается на сессии ...
Даниэль Лиуцци
19
но на практике информация для входа хранится в cookie-файле, помеченном httponlyатрибутом, чтобы предотвратить некоторые риски xss, что означает, что его можно сбросить только с сервера (если не считать ручную очистку cookie-файла)
Remus Rusanu
6
«Вручную», как и пользователь, заходит в настройки браузера и выбирает опцию «Очистить куки». Вряд ли приемлемый способ «выйти» из веб-сайта.
Ремус Русану
1
@Remus Аааа, как прославленный веб-браузер делает написание веб-приложений таким болезненным.
Даррел Миллер
1
@DarrelMiller да, однако не отмена JWT на стороне сервера является уязвимостью безопасности. Даже если токены не хранятся на сервере, они должны быть помещены в черный список, когда пользователь выходит из системы / меняет пароли / меняет роли / выходит / и т.д., чтобы предотвратить злоупотребления (по крайней мере, до истечения срока их действия).
java-addict301
39

Одним из способов GETзлоупотребления здесь может быть то, что человек (возможно, конкурент :) разместил в Интернете тег с изображением src="<your logout link>"ЛЮБОГО ВЕЗДЕ, и если пользователь вашего сайта наткнется на эту страницу, он будет по незнанию отключен от системы.

raveren
источник
4
Нет, это не правильно. Ссылка на выход из системы будет работать только в том случае, если отправлены правильные данные cookie, которых не будет из другого домена. И даже если идентификатор сессии хранится в URL, это также не сработает, так как они меняются для каждой сессии.
Ричард Х
4
Вау, я никогда не думал об этом! Так что есть еще одна причина не использовать GET и еще одна причина, по которой я не понимаю, почему все это делают. Черт возьми, теперь я вынужден включить в мой пост stackoverflow.com/users/logout «image» и посмотреть, что произойдет :-D
Даниэль Лиуцци,
24
src = это простой запрос браузера, он приходит не со стороны сервера, а со стороны клиента. Он несет все куки и исходит от пользователя IP. Вот почему пиксели отслеживания рекламы работают. Единственным способом определить такой эксплойт будет проверка реферера.
raveren
12
SuperLogout.com делает именно это (загружает /logoutURL-адреса в скрытых изображениях), и это работает.
Дан Даскалеску
9
Re: SuperLogout ... Я не знаю, почему я нажал на это.
МИ Райт
21

Чтобы быть точным, GET / POST (или другие глаголы) являются действиями над некоторым ресурсом (адресуемым URL-адресом), так что обычно речь идет о состоянии ресурса, а не о состоянии приложения как такового. Таким образом, в истинном настроении у вас должен быть URL, например [host name]\[user name]\session, тогда «DELETE» будет правильным глаголом для действия выхода из системы.

Использование в [host name]\bla bla\logoutкачестве URL не совсем полноценного REST (IMO), так зачем спорить о правильном использовании GET / POST для него?

Конечно, я также использую GET для выхода из URL в своих приложениях :-)

VinayC
источник
2
В этом случае я бы сказал, что наличие части [имя пользователя] в URL кажется ненужным, поскольку пользователи всегда выходят из системы (т. Е. Удаляют) из своего собственного сеанса; никогда других пользователей ':-)
Даниэль Лиуцци
1
Не совсем - мы говорим, что сессия - это ресурс, и мы хотим его удалить. Таким образом, для единообразной адресации к любому сеансу вам необходимо иметь имя пользователя в составе URL. Ваш аргумент так же хорош, как если бы вы сказали, что выполнение действия PUT для [фотогалереи] \ pictures означает, что вы добавляете свои фотографии (доступно в [фотогалерее] \ [имя пользователя] \ pictures). Различные ресурсы должны быть адресованы явно, в них не может быть никакой неявности. Сайт может позволять другим пользователям добавлять изображения в вашу галерею - это будет частью контроля доступа, точно так же, как вы можете иметь суперпользователя, который может убивать чьи-либо сессии.
VinayC
1
С философской точки зрения, сессии и фотографии можно назвать «ресурсами», но на самом деле я бы не стал относиться к ним одинаково. Сеанс всегда изначально ограничен текущим пользователем (отсюда и название Сессия), и, по крайней мере, в ASP.NET, нет способа доступа к сеансам другого пользователя. Даже разработчик приложения не имеет прямого способа перечисления всех активных сеансов или средств для уничтожения сеансов по отдельности. Вы можете перезапустить приложение, чтобы убить все сеансы (InProc), но я бы не назвал этот контроль доступа. Помимо URL, вопрос все еще остается: ПОЛУЧИТЬ или ПОСТИТЬ?
Даниэль Лиуцци
Ресурс, следовательно, его адрес (URL) являются важной частью REST. Поэтому, если вы выберете URL, как я сказал, DELETE станет правильным словом, а не GET или POST. Кроме того, даже если вы ограничиваете себя ASP.NET, вы всегда можете иметь своего собственного провайдера состояний, который может дать вам возможность перечислять через сеансы и при необходимости уничтожать другие сеансы. Для готовых сессий in-proc некоторая путаница в global.asax должна дать вам функциональность. На самом деле вопрос в том, понадобится ли такая функциональность или нет. В редких случаях люди, как правило, перезапускают веб-сайт, чтобы выгнать людей с сайта.
VinayC
Это имеет смысл для меня. Дайте веб-интерфейсу сеансовый маршрут и вызовите на нем УДАЛИТЬ. Будь то ../session или ../session/current. Thankx @VinayC
Саймон Хупер
16

Выход из системы никак не влияет на само приложение. Изменяет состояние пользователя по отношению к приложению. В этом случае кажется, что ваш вопрос больше основан на том, как команда должна быть инициирована пользователем, чтобы начать это действие. Поскольку это не «разрушительное действие», убедитесь, что сеанс отменен или уничтожен, но ни ваше приложение, ни ваши данные не изменены, поэтому невозможно, чтобы оба метода инициировали процедуру выхода из системы. Сообщение должно использоваться любыми действиями, инициированными пользователем (например, пользователь нажимает кнопку «Выйти»), в то время как get может быть зарезервировано для инициированных приложением выходов из системы (например, - исключение, обнаруживающее потенциальное вторжение пользователя, принудительно перенаправляет на страницу входа с выходом из системы GET ).

Джоэл Этертон
источник
Интересно; Я никогда не думал об этом таким образом. +1.
Страгер
Это может предположительно зависеть от приложения (какое-то поведение «каскадного удаления»), но вы правы.
Андрес Яан Так
@JoelEtherton Спасибо, Джоэл, я читал ответы, задаваясь вопросом, когда я доберусь до правильного. :)
Кирилл Фукс
4
Это сбивает с толку, потому что выход из системы изменяет состояние. POST - глагол для изменения состояния. GET для получения данных без сохранения состояния. Это сбивает с толку, потому что мы ожидаем, что запросы POST будут иметь полезную нагрузку. Как отмечено ниже, DELETE будет наиболее правильным для объекта сеанса.
Майкл Коул
1
@MichaelCole: Я согласен с этим представлением о трудностях между POST и GET. Я не согласен с использованием глагола DELETE. DELETE предназначен для обработки ресурса, и в этом смысле сеанс не является ресурсом. Подумайте, если вы можете УДАЛИТЬ это, то вы также должны быть в состоянии ПОЛОЖИТЬ это.
Джоэл Этертон
16

Здравствуйте, с моей точки зрения, когда вы входите в систему, вы проверяете имя пользователя / пароль и, если они совпадают, вы создаете токен для входа.

CREAT token => метод POST

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

УДАЛИТЬ токен => метод УДАЛИТЬ

miorey
источник
4
Интересный угол.
Drumbeg
1
Я использую этот метод в моих приложениях Spring Boot REST.
Please_Dont_Bully_Me_SO_Lords
1
семантически правильно. Я согласен ...
DAG
1

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

Или, может быть, ссылка может быть реализована в JavaScript?

Изменить: Как я понимаю, технически GET должен быть для запросов только для чтения, которые не изменяют состояние приложения. POST должен быть для запросов на запись / редактирование, которые изменяют состояние. Однако другие проблемы приложения могут предпочесть GET, а не POST для некоторых запросов на изменение состояния, и я не думаю, что есть какие-либо проблемы с этим.

Ричард Х
источник
Спасибо. Состояние БД не будет изменено, но состояние сеанса будет. Единственная проблема, которую я вижу, это та, о которой я упомянул в вопросе, о том, что пользователей выгнали. Неразрушающий, но довольно раздражающий. Обычно я также говорю мантру «если большие парни делают это, значит, все в порядке». Я просто хотел узнать мнение других по этому поводу.
Даниэль Лиуцци
0

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

обкрадывать
источник
Не могли бы вы разработать «сценарий выхода из системы»? Я не уверен, что вы имеете в виду настройку срока действия файлов cookie (что не исключает необходимости предоставления пользователям возможности вручную выйти из системы).
Даниэль Лиуцци,
Сценарий выхода из системы завершит сеанс пользователя (на самом деле: браузер), вызывающего его. В ASP.net сеанс является объектом на стороне сервера, от которого можно отказаться. PHP имеет похожую систему. Поскольку этот браузер вызывает скрипт, который завершает сеанс, он уже знает, какой из них завершить, устраняя необходимость в переменных POST или GET.
Роб
1
Да, я понимаю тебя сейчас. У меня уже есть сценарий, в частности, FormsAuthentication.SignOut (), но мой вопрос о том, как вызвать сценарий, как в GET или POST.
Даниэль Лиуцци
О, у вас есть URL в форме? Неважно, если вы не передаете информацию. Худшее, что может случиться, - это когда кто-то вручную открывает скрипт и выходит из системы. Я бы даже не сделал это полем формы, если бы не было необходимости, ссылка на скрипт также работала бы. Если вы действительно отправляете информацию в скрипт, я бы, вероятно, пошел на POST, чтобы не показывать никакой информации пользователю (если они не просматривают исходный код страницы), и если они обновятся, они получат предупреждение от своего браузера (срок действия страницы истек), что может быть желательно.
Роб
0

Недавно я работал над проектом, использующим GET для выхода из системы. Ниже приведен код в Nodejs Express, и он прекрасно работает.

ваш router.js

const express = require("express");
router.get("/signout", signout);

ваш controller.js

exports.signout  = (req, res) => {
        res.clearCookie('t'); //clearing cookie, which is 
            //assign to the user during sign in.          
            res.json({message : 'Signout success'});   
        };
xSachinx
источник
-2

Я не вижу, как выход из системы (снижение прав доступа пользователей) является деструктивным действием. Это связано с тем, что действие «выход из системы» должно быть доступно только пользователям, которые уже вошли в систему, иначе оно будет устаревшим.

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

jpluijmers
источник
2
wgetв режиме паука с правильным файлом cookie сеанса на частной вики я должен был однажды сделать это. Конечно, один из первых просканированных URL был /logout.
Хельги
5
Попробуйте зайти на SuperLogout.com, чтобы увидеть, насколько разрушительными являются запросы GET к /logoutстраницам. Например, вам придется снова войти в Gmail, снова войти в чат, найти свое место в любых разговорах в Hangouts, которые вы прокручивали и т. Д., И это только для Google.com.
Дан Даскалеску