Czy MVC / REST powinien zwrócić 403 lub 404 dla zasobów należących do innych użytkowników?

33

Podczas pracy z witryną opartą na zasobach (taką jak aplikacja MVC lub usługa REST) ​​mamy dwie główne opcje, gdy klient próbuje GETuzyskać zasób, do którego nie ma dostępu:

  • 403 , który mówi, że klient jest nieautoryzowany ; lub
  • 404 , który mówi, że zasób nie istnieje (lub nie można go zlokalizować).

Powszechną mądrością i powszechną praktyką wydaje się być odpowiadanie na prawdę - to znaczy 403. Zastanawiam się jednak, czy tak naprawdę należy to zrobić.

Bezpieczne systemy logowania nigdy nie podają przyczyny niepowodzenia logowania. Oznacza to, że w przypadku klienta nie ma wykrywalnej różnicy między nieistniejącą nazwą użytkownika a niepoprawnym hasłem. Ma to na celu uniemożliwienie wykrycia identyfikatorów użytkowników - lub, co gorsza, adresów e-mail.

Z punktu widzenia prywatności znacznie bezpieczniej jest zwrócić 404. Przypomina mi się incydent, w którym ktoś podobno znalazł zwycięzców reality show (myślę, że Survivor), sprawdzając, które zasoby nie istniały na witryna vs. które. Niepokoi mnie fakt, że 403 potencjalnie ujawnia poufne informacje, takie jak numer seryjny lub numer konta.

Czy istnieją ważne powody, aby nie zwracać 404? Czy polityka 404 może mieć negatywne skutki uboczne w innym miejscu? Jeśli nie, to dlaczego praktyka nie jest bardziej powszechna?

Aaronaught
źródło
1
Niezbędny powód, aby nie zwracać 404: jeśli usługa jest wyłączona lub występuje błąd / błąd uwierzytelnienia, otrzymasz 404, ale klient / użytkownik / tester / programista / osoba wsparcia próbująca zdiagnozować problem może nie mieć pojęcia co jest nie tak z komunikatu o błędzie.
Steven Evers
@Snorfus: To dobra uwaga - udzieliłbym odpowiedzi. Chociaż Josh dodał już dobry kontrapunkt ...
Aaronaught
Innym aspektem, o którym należy pamiętać, jest to: w jaki sposób 404 traktowane są na dalszych etapach? Czy istnieje CDN lub jakieś buforowanie? Jeśli kiedykolwiek będziesz chciał móc je buforować, prawdopodobnie nie chcesz, aby twój „użytkownik nie miał uprawnień” do buforowania 404.
pc1oad1etter 26.11.11

Odpowiedzi:

15

Istnieje ogólne nieporozumienie (i niewłaściwe użycie) 403 Forbidden: nie powinno ono zdradzać niczego, co serwer myśli o żądaniu. Jest specjalnie zaprojektowany, aby powiedzieć:

Rozumiem, o co prosisz, ale nie zamierzam obsłużyć żądania, bez względu na to, czego spróbujesz. Więc przestań próbować.

Każdy UA lub klient powinien interpretować to w ten sposób, że żądanie nigdy nie zadziała i odpowiednio odpowiedzieć.

Ma to wpływ na klientów obsługujących żądania w imieniu użytkowników: jeśli użytkownik nie jest zalogowany lub się pomyli, klient obsługujący żądanie powinien odpowiedzieć: „Przepraszam, ale nic nie mogę zrobić” po raz pierwszy dostaje 403i przestaje obsługiwać przyszłe żądania. Oczywiście, jeśli chcesz, aby użytkownik nadal mógł żądać dostępu do swoich danych osobowych po awarii, jest to zachowanie wrogie użytkownikowi.

403Jest to w przeciwieństwie do 401 Authorization Required, który ma oddać, że serwer będzie obsługiwać żądania dopóki przechodzą odpowiednie uprawnienia. O tym zwykle myślą ludzie, kiedy słyszą 403.

Kontrastuje to również z 404 Page Not Foundtym, jak zauważyli inni, nie tylko po to, by powiedzieć „nie mogę znaleźć tej strony”, ale także po to, by zasugerować klientowi, że serwer nie wysyła żadnych roszczeń o sukces lub porażkę dla przyszłych żądań.

Za pomocą 401i 404, serwer nie mówi nic klientowi ani UA o tym, jak powinni postępować: mogą próbować w nadziei na inną odpowiedź.

404Jest to zatem odpowiedni sposób obsługi strony, której nie chcesz pokazywać wszystkim, ale nie chcesz zdradzać niczego, dlaczego nie chcesz jej pokazywać w określonych sytuacjach.

Oczywiście zakłada to, że klient składający wniosek troszczy się o drobną awanturę w RFC. Wystarczająco złośliwy klient nie będzie dbał o zwrócony kod stanu, chyba że w sposób przypadkowy. Można wiedzieć, że jest to ukryta strona użytkownika (lub potencjalnie ukryta strona użytkownika), porównując ją z innymi znanymi stronami użytkowników.

Powiedzmy, że twój przewodnik jest users/*. Jeśli wiem users/foo, users/bari users/baazpraca, serwer przekazujących 401, 403lub 404na users/quuxnie znaczy, że nie zamierzam spróbować, szczególnie jeśli mam powody, by sądzić, że jestquux użytkownika. Standardowym przykładem jest Facebook: mój profil jest prywatny, ale moje komentarze do profili publicznych nie są. Złośliwy klient wie, że istnieję, nawet jeśli wrócisz 404na stronę mojego profilu.

Dlatego kody statusu nie są przeznaczone dla przypadków złośliwego użycia, lecz dla klientów grających zgodnie z regułami. A dla tych klientów najbardziej odpowiednia jest prośba 401lub 404żądanie.


źródło
4
Dobre punkty o 401 vs. 403. Nie zgadzam się jednak z ostatecznością twoich wypowiedzi na 404. Jasne, na przykładzie Facebooka już wiesz, że quuxistnieje. Ale nie zawsze będą istnieć zewnętrzne dowody, szczególnie na nie-społecznościowych stronach, gdzie dane klientów są naprawdę prywatne . Wścibski lub wrogie użytkownik może ostatecznie być w stanie wydedukować , że kłamiesz, ale niekoniecznie których zasoby leżysz temat . Myślę, że istotną kwestią jest tutaj, nie przejmuj się 404 zasobami, chyba że nie są dostępne inne metody odkrywania.
Aaronaught
@Aaronaught Chodzi o to, że musisz być naprawdę, naprawdę pewien , że ktoś nie może dowiedzieć się, o co serwer oszukuje, lub że nie ma żadnej metody odkrywania, przed którą się nie stwardniałeś. To wystarczająco inteligentna osoba będzie zrozumieć to, iw tym momencie, kod stanu jest bez znaczenia.
1
Nadal nie jestem pewien, w jaki sposób wystarczająco inteligentna osoba może to zrozumieć, jeśli nie ma udostępniania danych między profilami użytkowników. Rozumiem, że ktoś zdeterminowany w końcu zda sobie sprawę „och, 404 faktycznie oznacza, że ​​może istnieć, ale po prostu nie mogę uzyskać do niego dostępu” - ale zakładając, że serwer zwraca ten sam błąd dla zasobów, które naprawdę nie istnieją, jak by to było odróżnić nieistniejący zasób od uprzywilejowanego?
Aaronaught
@Aaronaught jedyną rzeczą, którą powinna wiedzieć osoba, jest adres URL profilu. Możesz po prostu używać identyfikatorów profili i zwiększać je w pseudo-stylu (więc osoba o identyfikatorze profilu 3333 nie oznacza, że ​​jest osoba o identyfikatorze profilu 3332), ale określona osoba powinna być w stanie przewidzieć to, biorąc pod uwagę pewne przykładowy rozmiar prawidłowych identyfikatorów. W przeciwnym razie, a nawet biorąc pod uwagę całkowicie zahartowany system, który nie wycieka żadnych informacji o tym, jak generuje adresy URL stron profilowych, zawsze istnieje socjotechnika.
8

Zgodnie z RFC2616

10.4.4 403 Zabronione

Serwer zrozumiał żądanie, ale odmawia jego spełnienia. Autoryzacja nie pomoże, a prośba NIE POWINNA zostać powtórzona. Jeśli metoda żądania nie była HEAD, a serwer chce podać do publicznej wiadomości, dlaczego żądanie nie zostało spełnione, POWINIEN opisać przyczynę odmowy w jednostce. Jeśli serwer nie chce udostępnić tych informacji klientowi, zamiast tego można użyć kodu stanu 404 (Nie znaleziono).

należy również pamiętać, że podczas uzyskiwania dostępu do zabronionych zasobów autoryzacja nie pomoże .

Lie Ryan
źródło
Zdaję sobie sprawę z RFC, chociaż mało przypomina on rzeczywistość. Prawie żaden serwer nigdy nie wyjaśnia przyczyny 403 poza tym pierwszym zdaniem („Serwer zrozumiał żądanie, ale odmawia jego spełnienia.”), A większość platform MVC ma nawet coś podobnego do HttpUnauthorizedResulttego, co jest przeznaczone do wykorzystania w uprzywilejowanych zasobach . Zdaję sobie również sprawę (oczywiście), że zamiast tego można użyć 404 ; moje pytanie brzmi, czy należy go użyć i co należy wziąć pod uwagę przy podejmowaniu tej decyzji.
Aaronaught
@Aaronaught: RFC nie tylko pozwala na użycie 404, ale zaleca rzucanie 404, gdy nie chcesz niczego potwierdzać.
Lie Ryan
3
W porządku, ale kiedy nie powinienem nic potwierdzać? A raczej kiedy powinienem ? To naprawdę istota pytania.
Aaronaught
5

Powinieneś? Tak .

Sam to powiedziałeś, zdradzaj jak najmniej. Gdybym atakował system i zauważył, że serwer odpowiedział kodami 403, skupiłbym się na nich, zamiast iść dalej. Lepiej, aby drzwi głosiły, że nie istnieje, a następnie ogłosić, że zostaną zablokowane.

Wadą korzystania z 404 żądań jest to, że na zewnątrz będzie wyglądać, jakby strona nie istniała, i może to powodować konflikty w porównaniu ze stronami, które powinny istnieć, ale zamiast nich. Jeśli nie przejmujesz się robotami indeksującymi (systemy uwierzytelnione i tak powinny zostać całkowicie odrzucone), powinieneś absolutnie to zrobić. Każdy interfejs API, który mam, obsługuje nieautoryzowany dostęp dokładnie w ten sam sposób, podobnie jak StackOverflow . Nie widzisz tej strony? Zapewniam cię, że nie istnieje, mimo że nie twierdzi.

Państwo powinno uznać żądań, gdy zasób jest znany istnieć i odmowa dostępu. Nieudane logowanie nie powinno skutkować komunikatem 404. Nie należy potwierdzać żądań, gdy istnienie samego zasobu powinno być chronione. Dostęp do dziedziny istnieje publicznie, ale grupy zabezpieczeń lub role w niej nie istnieją.


Niezbędny powód, aby nie zwracać 404: jeśli usługa jest wyłączona lub występuje błąd / błąd uwierzytelnienia, otrzymasz 404, ale klient / użytkownik / tester / programista / osoba wsparcia próbująca zdiagnozować problem może nie mieć pojęcia co jest nie tak z komunikatu o błędzie

Programiści powinni mieć dostęp do dzienników, co wskaże na próbę uzyskania dostępu do chronionego zasobu. Klienci / Użytkownicy / Testerzy będą generować informacje zwrotne, które ostatecznie trafią w programistę.

Bezpieczeństwo przez zaciemnienie ... naprawdę?

To nie jest bezpieczeństwo przez zaciemnienie. Oprócz odpowiednich środków bezpieczeństwa używasz niejasności .

Z drugiej strony prawidłowe żądania otrzymujące „404” dodają złożoności i niejasności tam, gdzie nie jest to konieczne

Nie są prawidłowymi żądaniami, są nieautoryzowanymi żądaniami. Zmieniasz niewielką część (zwracasz 404 zamiast 403), aby zyskać znaczną przewagę wśród potencjalnych przyszłych atakujących.

Josh K.
źródło
Bezpieczeństwo przez zaciemnienie ... naprawdę? Jeśli ktoś próbuje wyłudzić twoje usługi ze złośliwych zamiarów, już wie, że one tam są. Z drugiej strony prawidłowe żądania otrzymujące „404” dodają złożoności i niejasności tam, gdzie nie jest to konieczne.
Steven Evers
4
@ Snorfus: Należy wprowadzić subtelne rozróżnienie między bezpieczeństwem a prywatnością . Prywatność to prawie z definicji „niejasność”. Jest to szczególnie ważne w kontekście systemu opartego na zasobach , ponieważ istnienie lub brak zasobu jest potencjalnie ważną informacją. Mogą istnieć również argumenty dotyczące bezpieczeństwa, chociaż mniej się nimi przejmuję. I będzie chciał usłyszeć więcej o tej dodatkowej złożoności; czy możesz przejść do szczegółów poza początkowym komentarzem? (Być może w bardziej wyczerpującej odpowiedzi? Czy zostałeś ugryziony przez 404'ed 403?)
Aaronaught
2
@Snorfus: Chciałbym również dodać, że późniejsza obrona w głębi nie jest tym samym, co ochrona przez zaciemnienie . To ostatnie sugeruje, że nie ma innych środków ochrony. Ale dodanie zaciemnienia do już zabezpieczonego systemu może często być dobrą rzeczą - pod warunkiem, że nie spowoduje to innych problemów w przyszłości. W tym przypadku chodzi o to, że system jest już zabezpieczony, ponieważ 404 są emitowane przez kod autoryzacyjny.
Aaronaught
@Aaronaught: Prześlę bardziej dogłębną odpowiedź, ale na temat: jeśli zasób jest prywatny, jaki jest powód ujawnienia go publicznie?
Steven Evers
@ Snorfus: Zasób jest prywatny dla klienta - a może dla grupy - nie dla całego świata.
Aaronaught
0

To naprawdę zależy od informacji przekazywanych przez kod statusu 403. Jeśli masz punkt końcowy interfejsu API odpowiadający GET /myresource/{id}404, gdy zasób nie istnieje, kod stanu zwrócony przez punkt końcowy, gdy zasób istnieje, ale nie jest autoryzowany dla bieżącego użytkownika, powinien zależeć od przewidywalności idparametru i ilości zawartych w nim informacji.

  • Jeśli idjest to pole prywatne, takie jak adres e-mail lub numer konta bankowego, prawdopodobnie powinno zawsze być ukryte za 404. W przypadku adresu e-mail może to uniemożliwić robotom spamującym zestawienie listy prawidłowych adresów e-mail zarejestrowanych w Twojej witrynie.
  • Jeśli idjest to publiczna nazwa użytkownika, nie przejmuj się, istnieją inne sposoby uzyskania dostępu do tych informacji (np. Przeglądając stronę forum swojej witryny).
  • Jeśli idjest nieprzejrzystym, ale przewidywalnym identyfikatorem (np. Liczbą całkowitą z auto-inkrementacją), nie przekazujesz atakującemu żadnych informacji, których nie mógłby uzyskać w inny sposób. Dlatego moim zdaniem bezpiecznie jest zwrócić kod stanu 403.
  • Jeśli idjest nieprzejrzystym, nieprzewidywalnym identyfikatorem (jak losowy identyfikator GUID), pytanie jest bardziej subtelne. Osobiście uważam, że nie ma problemu ze zwrotem kodu stanu 403. Informacje te można wykorzystać tylko wtedy, gdy istnieje inny wadliwy punkt końcowy w interfejsie API używającym tego identyfikatora, ale prawdziwą wadą jest Twój drugi punkt końcowy.

Możesz założyć, że lepiej jest w każdym razie być bezpiecznym niż żałować i ukryć informacje bez względu na kontekst, ale tak naprawdę nie możesz polegać na tego rodzaju zachowaniu, aby zapewnić jakąkolwiek formę bezpieczeństwa . Z drugiej strony może zapewniać poufność (lub prywatność, jak powiedzieli inni).

Mechanizm bezpieczeństwa nie powinien być dla atakującego jedynie ograniczeniem prędkości, w przeciwnym razie jest po prostu bezużyteczny. W takim przypadku może nawet uniemożliwić prawidłowe korzystanie z innych funkcji (przeszukiwacze, zapora aplikacji sieci Web szukają nieprawidłowych ilości kodów stanu 403 w celu zablokowania użytkowników ...).

Maxime Rossini
źródło