MVC / REST dovrebbe restituire un 403 o 404 per risorse appartenenti ad altri utenti?


33

Quando si lavora con un sito basato su risorse (come un'applicazione MVC o un servizio REST), abbiamo due opzioni principali quando un client tenta di GETaccedere a una risorsa a cui non ha accesso:

  • 403 , che afferma che il cliente non è autorizzato ; o
  • 404 , che indica che la risorsa non esiste (o non è stata individuata).

La saggezza comune e la pratica comune sembrano essere di rispondere con la verità, cioè una 403. Ma mi chiedo se questa sia effettivamente la cosa giusta da fare.

I sistemi di accesso sicuro non ti dicono mai il motivo di un errore di accesso. Vale a dire, per quanto riguarda il client, non vi è alcuna differenza rilevabile tra un nome utente inesistente e una password errata. Lo scopo è di non rendere identificabili gli ID utente, o peggio, gli indirizzi e-mail.

Dal punto di vista della privacy , sembra molto più sicuro restituire un 404. Mi viene in mente l'incidente in cui si dice che qualcuno abbia scoperto i vincitori di un reality show (Survivor, credo) osservando quali risorse non esistevano sul sito vs. quali lo hanno fatto. Sono preoccupato per un 403 che potenzialmente fornisce informazioni sensibili come un numero di serie o un numero di conto.

Ci sono validi motivi per non restituire un 404? Una politica 404 potrebbe avere effetti collaterali negativi altrove? In caso contrario, perché la pratica non è più comune?


1
Motivo convincente di non restituire 404: se il servizio è inattivo o c'è un bug / errore nell'autenticazione, si otterrebbe un 404, ma il cliente / utente / tester / sviluppatore / persona di supporto che tenta di diagnosticare il problema potrebbe non avere idea cosa c'è di sbagliato nel messaggio di errore.
Steven Evers,

@Snorfus: Questo è un buon punto - lo avrei inserito in una risposta. Anche se Josh ha già aggiunto un buon contrappunto ...
Aaronaught l'

Un altro aspetto da tenere a mente è questo: come vengono trattati a valle i 404? Esiste un CDN o un qualche tipo di memorizzazione nella cache? Se mai vuoi essere in grado di memorizzarli nella cache, probabilmente non vuoi che il tuo "utente non abbia i permessi" venga memorizzato nella cache.
pc1oad1etter,

Risposte:


15

C'è un malinteso generale (e un uso improprio) associato 403 Forbidden: non si suppone che dia via ciò che il server pensa della richiesta. È specificamente progettato per dire,

Ho quello che stai chiedendo, ma non gestirò la richiesta, qualunque cosa tu provi. Quindi smetti di provare.

Qualsiasi UA o cliente dovrebbe interpretarlo nel senso che la richiesta non funzionerà mai e rispondere in modo appropriato.

Ciò ha implicazioni per i clienti che gestiscono le richieste per conto degli utenti: se un utente non ha effettuato l'accesso o errori di digitazione, il cliente che gestisce la richiesta dovrebbe rispondere "Mi dispiace, ma non posso fare nulla" dopo la prima volta ottiene 403e smette di gestire le richieste future. Ovviamente, se si desidera che un utente sia ancora in grado di richiedere l'accesso alle proprie informazioni personali dopo un errore, si tratta di un comportamento ostile all'utente.

403è in contrasto con 401 Authorization Required, che non dare via che il server gestirà la richiesta fino a quando si passa le credenziali corrette. Questo è di solito ciò a cui la gente pensa quando sente 403.

È anche in contrasto con il 404 Page Not Foundquale, come altri hanno sottolineato, è stato progettato non solo per dire "Non riesco a trovare quella pagina", ma per suggerire al client che il server non fa dichiarazioni di successo o fallimento per richieste future.

Con 401e 404, il server non dice nulla al client o UA su come dovrebbero procedere: possono continuare a provare nella speranza di ottenere una risposta diversa.

Quindi 404è il modo appropriato di gestire una pagina che non vuoi mostrare a tutti, ma non vuoi dare niente sul perché non la mostrerai in determinate situazioni.

Ovviamente, ciò presuppone che il cliente che si occupa della richiesta si preoccupi della scarsa leggerezza della RFC. Un client abbastanza malizioso non si preoccuperà del codice di stato restituito se non in modo accidentale. Uno saprà che è una pagina utente nascosta (o una potenziale pagina utente nascosta) confrontandola con altre pagine utente note.

Cioè, supponiamo che sia il tuo gestore users/*. Se lo so users/foo, users/bare users/baazfunziona, il server che restituisce un 401, 403o 404per users/quuxnon significa che non lo proverò, soprattutto se ho motivo di credere che ci sia un quuxutente. Uno scenario di esempio standard è Facebook: il mio profilo è privato, ma i miei commenti sui profili pubblici non lo sono. Un client dannoso sa che esisto anche se ritorni 404sulla pagina del mio profilo.

Quindi i codici di stato non sono per i casi di utilizzo dannoso, sono per i client che giocano secondo le regole. E per quei clienti, una 401o una 404richiesta è la più appropriata.


4
Buoni punti su 401 contro 403. Non sono d'accordo con la finalità delle tue dichiarazioni su 404, comunque. Certo, nell'esempio di Facebook, sai già che quuxesiste. Ma non ci saranno sempre prove esterne, specialmente su siti non social in cui i dati dei clienti sono davvero privati . Un utente ficcanaso o ostile potrebbe alla fine essere in grado di dedurre che si sta mentendo, ma non necessariamente che le risorse si sono distesi su . Penso che il punto saliente qui sia davvero, non preoccuparti di 404 risorse a meno che non ci siano altri metodi di scoperta disponibili.
Aaronaught l'

@Aaronaught Il fatto è che devi essere davvero, davvero sicuro che qualcuno non riesca a capire di cosa si stia ingannando il server, o che non ci sia un metodo di scoperta a cui non ti sei mai opposto. Una persona abbastanza intelligente lo capirà e, a quel punto, il codice di stato non ha senso.

1
Non sono ancora chiaro su come una persona abbastanza intelligente potrebbe capirlo se non c'è condivisione di dati tra i profili utente. Capisco che qualcuno determinato alla fine realizzerà "oh, un 404 in realtà significa che potrebbe esistere, ma non riesco ad accedervi" - ma supponendo che il server restituisca lo stesso errore per le risorse che non esistono realmente , come si farebbe dire la differenza tra una risorsa inesistente e una privilegiata?
Aaronaught l'

@Aaronaught l'unica cosa che una persona dovrebbe sapere è che dovrebbe esistere l'URL di un profilo. Potresti semplicemente usare gli ID profilo e incrementarli in modo pseudo (quindi una persona con un ID profilo di 3333 non significa che c'è una persona con un ID profilo di 3332), ma una persona determinata dovrebbe essere in grado di prevederlo dato alcuni dimensione del campione di ID validi. In mancanza, e persino dato un sistema completamente rinforzato che non perde informazioni su come genera URL per le pagine del profilo, c'è sempre social engineering.

8

Secondo RFC2616

10.4.4 403 Proibito

Il server ha compreso la richiesta, ma si rifiuta di soddisfarla. L'autorizzazione non aiuterà e la richiesta NON DOVREBBE essere ripetuta. Se il metodo di richiesta non era HEAD e il server desidera rendere pubblico il motivo per cui la richiesta non è stata soddisfatta, DOVREBBE descrivere il motivo del rifiuto nell'entità. Se il server non desidera rendere disponibili queste informazioni al client, è possibile utilizzare invece il codice di stato 404 (Not Found).

si noti inoltre che quando si accede a risorse vietate, l' autorizzazione non sarà di aiuto .


Sono a conoscenza della RFC, anche se ha poca somiglianza con la realtà. Quasi nessun server spiega mai la ragione di un 403 oltre quella prima frase ("Il server ha capito la richiesta, ma si rifiuta di soddisfarla") e la maggior parte dei framework MVC ha persino qualcosa di simile a HttpUnauthorizedResultquella destinata a essere utilizzata per risorse privilegiate . Mi rendo anche conto (ovviamente) che invece si può usare 404 ; la mia domanda è se dovrebbe essere usato o meno e cosa dovrebbe essere preso in considerazione quando si prende quella decisione.
Aaronaught l'

@Aaronaught: RFC non ti consente solo di usare 404, ma ti consiglia di lanciare 404 quando non vuoi riconoscere nulla.
Lie Ryan,

3
Va bene, ma quando non dovrei riconoscere nulla? O meglio, quando dovrei ? Questa è davvero l'essenza della domanda.
Aaronaught l'

5

Dovresti? .

L'hai detto tu stesso, tradisci il meno possibile. Se stavo attaccando un sistema e notassi che il server ha risposto con 403 codici, mi concentrerei su quelli, invece di andare avanti. Meglio che una porta proclami che non esiste allora che proclami che è vietata.

L'aspetto negativo dell'utilizzo di 404 richieste è che esternamente apparirà come se la pagina non esistesse, e questo potrebbe avere conflitti rispetto alle pagine che dovrebbero esistere ma che invece mancano. Se non sei preoccupato per i crawler web (i sistemi autenticati dovrebbero comunque essere completamente negati), dovresti assolutamente provarci. Ogni API che ho gestito accede non autorizzato allo stesso modo, così come StackOverflow . Non riesci a vedere quella pagina? Vi assicuro che non esiste, anche se non pretende di.

È necessario riconoscere le richieste quando è noto che la risorsa esiste e l'accesso è negato. Un accesso non riuscito non dovrebbe generare un messaggio 404. Non è necessario riconoscere le richieste quando è necessario proteggere l'esistenza della risorsa stessa. L'accesso al regno esiste in pubblico, ma i gruppi di sicurezza o i ruoli al suo interno non lo sono.


Motivo convincente di non restituire 404: se il servizio è inattivo o c'è un bug / errore nell'autenticazione, si otterrebbe un 404, ma il cliente / utente / tester / sviluppatore / persona di supporto che tenta di diagnosticare il problema potrebbe non avere idea cosa c'è di sbagliato nel messaggio di errore

Gli sviluppatori dovrebbero avere accesso ai registri, che indicheranno un tentativo di accedere a una risorsa protetta. I clienti / utenti / tester genereranno feedback che alla fine colpiranno uno sviluppatore.

Sicurezza per oscurità ... davvero?

Questa non è sicurezza per oscurità. Stai utilizzando l'oscurità oltre alle misure di sicurezza adeguate.

D'altra parte, le richieste valide che ottengono un "404" aggiungono complessità e oscurità laddove non è necessario

Non sono richieste valide, sono richieste non autorizzate . Stai cambiando una piccola parte (restituisci 404 invece di 403) per ottenere un sostanziale vantaggio in tutti gli aspiranti attaccanti.


Sicurezza per oscurità ... davvero? Se qualcuno sta cercando di colpire i tuoi servizi con intenzioni dannose, sanno già che è lì. D'altra parte, le richieste valide che ottengono un "404" aggiungono complessità e oscurità laddove non è necessario.
Steven Evers,

4
@Snorfus: qui c'è una sottile distinzione tra sicurezza e privacy . La privacy è, quasi per definizione, "per oscurità". Ciò è particolarmente importante nel contesto di un sistema basato sulle risorse , poiché l'esistenza o la non esistenza di una risorsa sono informazioni potenzialmente importanti. Potrebbero esserci anche argomenti di sicurezza, anche se sono meno interessato a questi. Mi piacerebbe sentire di più su questa complessità aggiunto; puoi approfondire oltre il tuo commento iniziale? (Forse in una risposta più completa? Sei stato morso da 404'ed 403s?)
Aaronaught l'

2
@Snorfus: Vorrei anche aggiungere, come ripensamento, che la difesa in profondità non è la stessa della sicurezza dell'oscurità . Quest'ultimo implica che non esistono altri mezzi di protezione. Ma aggiungere l'oscurità a un sistema già sicuro può spesso essere una buona cosa, purché non causi altri problemi lungo la strada. In questo caso, è un dato di fatto che il sistema è già protetto, poiché i 404 vengono emessi dal codice di autorizzazione.
Aaronaught l'

@Aaronaught: posterò una risposta più approfondita, ma sulla questione: se una risorsa è privata, qual è il ragionamento alla base dell'esposizione pubblica?
Steven Evers,

@Snorfus: una risorsa è privata per un cliente - o forse per un gruppo - non per il mondo intero.
Aaronaught l'

0

Dipende davvero dalle informazioni fornite dal codice di stato 403. Se si dispone di un endpoint API che risponde GET /myresource/{id}con un 404 quando la risorsa non esiste, il codice di stato restituito dall'endpoint quando la risorsa esiste ma non è autorizzato all'utente corrente dovrebbe dipendere dalla prevedibilità del idparametro e dalla quantità di informazioni che contiene da solo.

  • Se si idtratta di un campo privato come un indirizzo e-mail o un numero di conto bancario, probabilmente dovrebbe essere sempre nascosto dietro un 404. Nel caso di un indirizzo e-mail, potrebbe impedire ai robot spamming di compilare un elenco di indirizzi e-mail validi registrati sul tuo sito web.
  • Se idè un nome utente pubblico, non preoccuparti, ci sono altri modi per accedere a queste informazioni (ad esempio, semplicemente navigando nella pagina del forum del tuo sito Web).
  • Se si idtratta di un identificatore opaco, ma prevedibile (ad es. Un numero intero auto-incrementante), non si forniscono informazioni all'attaccante che non potrebbe ottenere con altri mezzi. Quindi secondo me è sicuro restituire un codice di stato 403.
  • Se si idtratta di un identificatore opaco e imprevedibile (come un GUID casuale), la domanda è più sottile. Personalmente penso che non ci siano problemi a restituire un codice di stato 403. Queste informazioni potrebbero essere sfruttate solo se nell'API è presente un altro endpoint difettoso che utilizza questo ID, ma il vero difetto è l'altro endpoint.

Puoi presumere che sia meglio prevenire che curare in ogni caso e nascondere le informazioni in qualsiasi contesto, ma in realtà non puoi fare affidamento su questo tipo di comportamento per fornire qualsiasi forma di sicurezza . D'altra parte, può fornire riservatezza (o privacy, come altri hanno già detto).

Un meccanismo di sicurezza non dovrebbe essere solo un ostacolo per l'attaccante, altrimenti è semplicemente inutile. In questo caso, potrebbe persino impedirti di utilizzare correttamente altre funzionalità (crawler, Web Application Firewall alla ricerca di quantità anomale di 403 codici di stato per bloccare gli utenti ...).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.