Должен ли MVC / REST возвращать 403 или 404 для ресурсов, принадлежащих другим пользователям?


33

При работе с ресурсным сайтом (таким как приложение MVC или служба REST) ​​у нас есть два основных варианта, когда клиент пытается GETиспользовать ресурс, к которому у него нет доступа:

  • 403 , в котором говорится, что клиент не авторизован ; или
  • 404 , который говорит, что ресурс не существует (или не может быть найден).

Кажется, что общая мудрость и обычная практика - отвечать правдой, то есть 403. Но мне интересно, действительно ли это правильно.

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

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

Есть ли веские причины не возвращать 404? Может ли политика 404 иметь негативные побочные эффекты в других местах? Если нет, то почему эта практика не более распространена?


1
Неопровержимая причина не возвращать 404: Если служба не работает или имеется ошибка / ошибка в аутентификации, вы получите 404, но клиент / пользователь / тестировщик / разработчик / специалист по поддержке, пытающийся диагностировать проблему, может и не догадываться что не так с сообщением об ошибке.
Стивен Эверс

@Snorfus: Это хороший момент - я бы поставил это в ответ. Хотя Джош уже добавил хороший контрапункт ...
Aaronaught

Еще один аспект, который нужно иметь в виду, заключается в следующем: как относиться к 404-м вниз по течению? Есть CDN или какое-то кеширование? Если вы когда-нибудь захотите иметь возможность их кэшировать, то, вероятно, вы не хотите, чтобы ваши 404 «пользователь не имеет разрешения» были кэшированы.
pc1oad1etter

Ответы:


15

Существует общее заблуждение (и неправильное использование), связанное с 403 Forbidden: оно не должно ничего выдавать о том, что сервер думает о запросе. Это специально разработано, чтобы сказать,

Я получаю то, что вы запрашиваете, но я не собираюсь обрабатывать запрос, независимо от того, что вы пытаетесь. Так что перестань пытаться.

Любой UA или клиент должен интерпретировать это как означающее, что запрос никогда не будет работать, и отвечать соответствующим образом.

Это имеет значение для клиентов, обрабатывающих запросы от имени пользователей: если пользователь не вошел в систему или неправильно набрал номер, клиент, обрабатывающий запрос, должен ответить «Извините, но я ничего не могу сделать» после первого раза он получает 403и перестает обрабатывать будущие запросы. Очевидно, что если вы хотите, чтобы пользователь по-прежнему мог запрашивать доступ к своей личной информации после сбоя, это поведение враждебно для пользователя.

403в отличие от 401 Authorization Required, что делает отдать , что сервер будет обрабатывать запрос до тех пор , как вы передаете правильные учетные данные. Об этом обычно думают люди, когда слышат 403.

Это также противоречит тому, 404 Page Not Foundчто, как отмечали другие, предназначено не только для того, чтобы сказать «я не могу найти эту страницу», но и для того, чтобы предложить клиенту, чтобы сервер не заявлял об успехе или неудаче для будущих запросов.

С помощью 401и 404, сервер ничего не говорит клиенту или агенту UA о том, как они должны действовать: они могут продолжать пытаться получить другой ответ.

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

Конечно, это предполагает, что клиент, делающий запрос, заботится о мелком подделке RFC. Достаточно злонамеренный клиент не будет заботиться о возвращенном коде состояния, кроме как случайным образом. Кто-то узнает, что это скрытая пользовательская страница (или потенциальная скрытая пользовательская страница), если сравнить ее с другими известными пользовательскими страницами.

То есть, скажем, ваш обработчик users/*. Если я знаю users/foo, users/barи users/baazработа, сервер возвращая 401, 403или 404для users/quuxне значит , что я не собираюсь попробовать, особенно если у меня есть основания полагать , что там естьquux пользователь. Стандартным примером сценария является Facebook: мой профиль закрытый, а мои комментарии в общедоступных профилях - нет. Вредоносный клиент знает, что я существую, даже если вы вернетесь 404на страницу моего профиля.

Таким образом, коды состояния предназначены не для случаев злонамеренного использования, а для клиентов, играющих по правилам. И для этих клиентов, 401или 404запрос является наиболее подходящим.


4
Хорошие моменты о 401 против 403. Хотя я не согласен с окончательностью ваших утверждений по 404. Конечно, на примере Facebook вы уже знаете, что quuxсуществует. Но не всегда будут внешние доказательства, особенно на сайтах, не относящихся к социальным сетям, где данные клиентов действительно являются конфиденциальными . Любопытное или враждебное пользователь может в конечном счете быть в состоянии вывести , что ты врешь, но не обязательно , которые ресурсами вы лжете о . Я думаю, что существенный момент здесь действительно, не беспокойтесь о 404 ресурсах, если нет других доступных методов обнаружения.
Aaronaught

@Aaronaught Дело в том, что вы должны быть действительно уверены , что кто-то не может понять, в чем заключается обман сервера, или в том, что нет какого-то метода обнаружения, к которому вы не применили. Достаточно умный человек будет понять это, и в тот момент, код статуса не имеет смысла.

1
Я до сих пор не понимаю, как достаточно умный человек мог понять это, если нет обмена данными между профилями пользователей. Я понимаю, что кто-то определенно в конечном итоге поймет, «о, 404 на самом деле означает, что он может существовать, но я просто не могу получить к нему доступ» - но при условии, что сервер возвращает ту же ошибку для ресурсов, которые на самом деле не существуют, как бы Скажите разницу между несуществующим ресурсом и привилегированным?
Ааронаут

@Aaronaught единственное, что человеку нужно знать, это URL-адрес профиля должен существовать. Вы можете просто использовать идентификаторы профиля и увеличивать их псевдо-способом (так что человек с идентификатором профиля 3333 не означает, что есть человек с идентификатором профиля 3332), но определенный человек должен быть в состоянии предсказать его, учитывая некоторые Размер выборки действительных идентификаторов. В противном случае, и даже при наличии полностью защищенной системы, которая не дает информации о том, как она генерирует URL для страниц профиля, всегда есть социальная инженерия.

8

Согласно RFC2616

10.4.4 403 Запрещено

Сервер понял запрос, но отказывается его выполнить. Авторизация не поможет и запрос НЕ ДОЛЖЕН повторяться. Если метод запроса не был HEAD и сервер желает сообщить, почему запрос не был выполнен, он ДОЛЖЕН описать причину отказа в объекте. Если сервер не желает предоставлять эту информацию клиенту, вместо него можно использовать код состояния 404 (не найден).

Также обратите внимание, что при доступе к Запрещенным ресурсам авторизация не поможет .


Я знаю о RFC, хотя он мало похож на реальность. Почти ни один сервер никогда не объясняет причину появления 403 за этим первым предложением («Сервер понял запрос, но отказывается его выполнять»), и в большинстве сред MVC даже есть что-то похожее на то, HttpUnauthorizedResultкоторое предназначено для использования для привилегированных ресурсов. , Я также понимаю , (очевидно) , что 404 может быть использован вместо; мой вопрос , является ли он или нет , должен быть использован, и что следует учитывать при принятии этого решения.
Ааронаут

@Aaronaught: RFC не просто позволяет вам использовать 404, он рекомендует бросать 404, когда вы не хотите ничего подтверждать.
Ли Райан

3
Это хорошо, но когда я не должен ничего признавать? Или, скорее, когда я должен ? Это действительно суть вопроса.
Ааронаут

5

Вы должны? Да .

Ты сам сказал, предай как можно меньше. Если бы я атаковал систему и заметил, что сервер ответил 403 кодами, я бы сосредоточился на них, а не на том, чтобы двигаться дальше. Лучше дверь объявить, что она не существует, тогда объявить, что ее запретили.

Недостатком использования 404 запросов является то, что внешне это будет выглядеть так, как будто страница не существует, и это может привести к конфликтам по сравнению со страницами, которые, как предполагается, существуют, но отсутствуют. Если вы не беспокоитесь о веб-сканерах (аутентифицированные системы в любом случае должны быть полностью запрещены), тогда вам обязательно следует пойти на это. Каждый API, который у меня есть, обрабатывает неавторизованный доступ точно так же, как и StackOverflow . Не можете увидеть эту страницу? Уверяю вас , это действительно существует, хотя она утверждает , что не.

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


Неопровержимая причина не возвращать 404: если служба не работает или имеется ошибка / ошибка в аутентификации, вы получите 404, но клиент / пользователь / тестировщик / разработчик / специалист по поддержке, пытающийся диагностировать проблему, может и не догадываться что не так с сообщением об ошибке

Разработчики должны иметь доступ к журналам, в которых будет указана попытка доступа к защищенному ресурсу. Клиенты / пользователи / тестеры будут генерировать обратную связь, которая в конечном итоге ударит разработчика.

Безопасность по неизвестности ... правда?

Это не безопасность по неизвестности. Вы используете неизвестность в дополнение к надлежащим мерам безопасности.

Действительные запросы, получающие «404» с другой стороны, просто добавляют сложность и неясность, где это не нужно

Это не действительные запросы, это неавторизованные запросы. Вы меняете небольшую часть (верните 404 вместо 403), чтобы получить существенное преимущество у любых потенциальных нападающих.


Безопасность мраком ... правда? Если кто-то пытается подтолкнуть ваш сервис (ы) со злым умыслом, он уже знает, что он там есть. Действительные запросы, получающие «404» с другой стороны, просто добавляют сложность и неясность там, где это не нужно.
Стивен Эверс

4
@ Snorfus: Здесь следует проводить тонкое различие между безопасностью и конфиденциальностью . Конфиденциальность, почти по определению, "по неизвестности". Это особенно важно в контексте системы на основе ресурсов , поскольку наличие или отсутствие ресурса является потенциально важной информацией. Могут быть и аргументы в области безопасности, хотя я менее обеспокоен ими. Я хотел бы услышать больше об этой дополнительной сложности; Можете ли вы вдаваться в подробности помимо вашего первоначального комментария? (Возможно, в более всеобъемлющем ответе? Вас укусили 404-е и 403-е годы?)
Ааронаут

2
@Snorfus: Я также хотел бы добавить в качестве запоздалой мысли, что глубокая защита - это не то же самое, что защита от мрака . Последнее подразумевает, что других средств защиты нет. Но добавление неясности в уже защищенную систему часто может быть полезным, если только это не вызовет других проблем в будущем. В данном случае считается, что система уже защищена, поскольку 404-е излучаются кодом авторизации.
Aaronaught

@Aaronaught: я выложу более подробный ответ, но по вопросу: если ресурс является частным, то в чем причина публичного его раскрытия?
Стивен Эверс

@Snorfus: ресурс является частным для клиента - или, может быть, для группы - не для всего мира.
Ааронаут

0

Это действительно зависит от информации, предоставляемой кодом состояния 403. Если у вас есть конечная точка API, отвечающая GET /myresource/{id}404, когда ресурс не существует, то код состояния, возвращаемый конечной точкой, когда ресурс существует, но не авторизован для текущего пользователя, должен зависеть от предсказуемости idпараметра и количества информации, которую он содержит сам по себе.

  • Если idэто частное поле, такое как адрес электронной почты или номер банковского счета, оно, вероятно, всегда должно быть скрыто за 404. В случае адреса электронной почты это может помешать спам-ботам составить список действительных адресов электронной почты, зарегистрированных на вашем веб-сайте.
  • Если idэто публичное имя пользователя, не беспокойтесь, есть другие способы получить доступ к этой информации (например, просто просматривая страницу форума вашего сайта).
  • Если idэто непрозрачный, но предсказуемый идентификатор (например, автоинкрементное целое число), вы не передаете злоумышленнику информацию, которую он не мог получить другими способами. Так что, по моему мнению, можно вернуть код состояния 403.
  • Если idэто непрозрачный, непредсказуемый идентификатор (например, случайный идентификатор GUID), вопрос более тонкий. Я лично думаю, что нет проблем с возвратом кода состояния 403. Эта информация может быть использована только в том случае, если в вашем API есть другая дефектная конечная точка, использующая этот идентификатор, но реальным недостатком является ваша другая конечная точка.

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.