Le restrizioni di sicurezza dovrebbero rendere un servizio nullo o generare un'eccezione? [chiuso]


11

Sono un po 'in disaccordo con uno sviluppatore più esperto su questo problema e mi chiedo cosa ne pensano gli altri; il nostro ambiente è Java, EJB 3, servizi, ecc.

Il codice che ho scritto chiama un servizio per ottenere cose e creare cose. Il problema che ho riscontrato è che ho ricevuto eccezioni con puntatore null che non avevano senso. Ad esempio, quando chiedo al servizio di creare un oggetto, ottengo indietro nulla; quando provo a cercare un oggetto con un ID valido noto, ottengo indietro. Ho trascorso un po 'di tempo a cercare di capire cosa c'era di sbagliato nel mio codice; dal momento che sono meno esperto, di solito presumo di aver fatto qualcosa di sbagliato, ma si scopre che la ragione per i rendimenti nulli è stata la sicurezza. Se l'entità utente che utilizza il mio servizio non disponeva delle autorizzazioni giuste per il servizio di destinazione, restituisce semplicemente null. La maggior parte degli altri servizi qui non sono documentati molto bene, quindi apparentemente questo è solo qualcosa che devi sapere.

Questo è piuttosto confuso come uno sviluppatore che scrive codice che interagisce con il servizio. Avrebbe molto più senso per me se il servizio rappresentasse un'eccezione che mi direbbe che l'utente non aveva le autorizzazioni appropriate per caricare questa cosa o crearla; Vorrei quindi immediatamente sapere perché il mio servizio non funzionava come previsto.

Lo sviluppatore più esperto che ha scritto il servizio ha sostenuto che la richiesta dei dati non è una condizione di errore e che le eccezioni dovrebbero essere lanciate solo in una condizione di errore, non quando l'utente non ha accesso ai dati. Questi dati vengono spesso cercati in una GUI e per quegli utenti senza le giuste autorizzazioni, queste cose semplicemente "non esistono". Quindi, in breve: chiedere non è sbagliato, quindi non fa eccezione. I metodi get restituiscono null perché a quegli utenti queste cose "non esistono". I metodi di creazione restituiscono null quando l'utente non è stato autorizzato a creare quella cosa.

È normale e / o buona pratica? Preferisco usare le eccezioni perché trovo molto più facile sapere cosa sta succedendo. Quindi, ad esempio, preferirei anche lanciare NotFoundException se chiedessi un oggetto con un ID non valido, piuttosto che restituire null.



@ChrisF: 1) parla di persone che evitano riferimenti nulli, cosa che io no. In molti casi sono appropriati, non penso proprio che siano in questo. 2) si tratta di controllare i parametri e una sorta di asserzione non comporterebbe lo stesso risultato del lancio di un'eccezione? 3) le eccezioni rispetto ai codici di errore sono anche un problema diverso in quanto sono entrambi modi di "mostrare" ciò che è andato storto. I codici di errore sono appropriati se, ad esempio, è necessario notificare un sistema che non supporta le eccezioni o se non si desidera che l'utente finale veda altro che un codice.
Svish,

Il problema che mi chiedo qui riguarda "fingere che qualcosa non esista o non è accaduto" vs "dire perché qualcosa non esiste o non è accaduto".
Svish,

3
Non ho suggerito che fossero duplicati, solo che potrebbero avere informazioni utili per te.
ChrisF

Vero, scusa per quello! Lo prese come un commento "possibili duplicati" per qualche motivo ... probabilmente a causa della mancanza di sonno, hehe.
Svish,

Risposte:


19

Le eccezioni dovrebbero essere lanciate solo quando c'è un errore e chiedere una cosa non è un errore.

Chiedere una cosa potrebbe non essere un errore, ma non avere i permessi per qualcosa che hai chiesto è sicuramente una sorta di errore. Le eccezioni sono un modo alternativo per segnalare condizioni eccezionali, da utilizzare al posto di valori di ritorno speciali (come null, come , come hai scritto, non è assolutamente di aiuto se ci sono> 1 possibili ragioni per cui le cose potrebbero andare male (anche se ci sono esattamente 1 possibile motivo ora, potrebbero esserci 2 possibili motivi nella prossima versione, quindi l'utilizzo nullcome valore di ritorno che indica che il fallimento si sarebbe dipinto in un angolo)). Se il servizio non segnala in alcun modo perché non farà ciò che hai richiesto, allora è sicuramente un cattivo design.

Se utilizzare un valore di ritorno speciale (ad esempio numeri interi negativi sono utili per le funzioni che normalmente restituiscono un numero intero non negativo), un'eccezione, un gestore di errori globale o un logger ecc., È un dettaglio di implementazione alla fine. La scelta dipende dalla lingua, dalla situazione, dalle convenzioni ed è anche una questione di gusti. Il punto principale è che dovrebbe esserci un modo diretto per scoprire perché qualcosa non funziona. Altrimenti la tua unica opzione è quella di andare in giro con diverse opzioni e qualunque cosa per scoprire cosa è correlato al comportamento della scatola nera, ed è una perdita di tempo.

String.substring()genera un IndexOutOfBoundsExceptionse l'indice è fuori limite. Non riesco a pensare a nessun vantaggio al ritorno null, anche se - filosoficamente - si potrebbe sostenere che a Stringnon contenga nulla al di fuori dei suoi limiti, quindi allora nullsarebbe un valore di ritorno logico. Essere logico-filosofici ed essere pratici sono ovviamente due diversi animali.


Se la sottostringa () restituirà un valore per gli indici fuori limite, dovrebbe restituire la parte della stringa tra gli indici, possibilmente vuota. Ciò potrebbe salvare un test in un codice chiamante.
Kevin Cline,

2
Sì, esiste questo "valore vuoto" infinito rispetto a null -discussion: la sottostringa per gli indici non associati deve essere nulla o una stringa vuota? Non lo so, entrambi sono effettivamente "niente" (beh, forse null è "più niente" di una stringa vuota?), Ma non fornisce nemmeno la quantità di informazioni che un'eccezione fa.
Joonas Pulakka,

@kevincline: A meno che uno non stia utilizzando un framework in cui un riferimento null è un mezzo idiomatico per indicare una stringa vuota, non vedo alcuna base per substringrestituire un riferimento null. IMHO, dovrebbero esserci due funzioni separate - una delle quali promette di restituire il numero richiesto di caratteri o di generare un'eccezione, e una delle quali restituisce il più possibile. Ogni metodo sarebbe sostanzialmente superiore all'altro in alcuni contesti.
supercat

@supercat: non ho detto nulla sul ritorno a null. Ho detto 'ritorno ... la parte ... forse vuota'. Una stringa vuota non è nulla, tranne che per Oracle.
Kevin Cline,

@JoonasPulakka: avrei dovuto mandarti al mio commento precedente.
supercat

5

Dipende dal contratto. Se il tuo contratto dice che puoi richiedere qualcosa che non esiste, dovrebbe dire cosa succede (oggetto null o null).

D'altra parte, se il tuo contratto dice che dovresti prima chiamare un metodo diverso ( DoesSomethingExist()) e quindi chiamare il Getmetodo, allora il tuo contratto potrebbe dire che puoi ottenere solo cose che esistono e generare un'eccezione se non lo fanno. Il messaggio di eccezione potrebbe dire qualcosa del tipo "Assicurati di chiamare DoesSomethingExist()prima" che è un utile messaggio di errore.


In questo caso direi che non è normale chiedere qualcosa che non esiste, poiché probabilmente non chiederebbe un ID che non esiste. Di solito avresti prima ottenuto un elenco di cose e poi cercane una in particolare per maggiori dettagli. Quindi, se esistesse un findAllThingsmetodo, direi che è opportuno restituire un elenco vuoto o un sottoinsieme se ci sono alcune o tutte le cose che non ti è permesso vedere. Allo stesso modo, su un blog potrei elencare solo i post per la modifica appartenenti all'utente corrente. Ma se quell'utente ha quindi cercato di modificare l'URL e modificare un altro post ...
Svish

4

Non esiste una risposta unica per tutti alla domanda. Se utilizzare le eccezioni o restituire null dipende dalla situazione.

Invece di guardare questo puramente da un punto di vista dogmatico, guarda l'interfaccia come un'interfaccia utente . Le interfacce utente dovrebbero essere utilizzabili . Quindi, indipendentemente dalle tue opinioni sul modo "giusto" di fare qualcosa, scegli il metodo più utilizzabile dal punto di vista di qualcuno che usa la tua interfaccia.

Se il chiamante deve sapere perché un oggetto non viene restituito, un'eccezione è appropriata. Se, tuttavia, il concetto generale è "se non si dispone dell'autorizzazione, non esiste", il valore nullo è accettabile.

In particolare nel tuo caso, direi che i null sono perfettamente accettabili per la ricerca di un elemento se al chiamante viene richiesto per la prima volta di accedere o connettersi al server. Questo è quando ti verrà detto che hai o non hai il permesso. Una volta superato il cancello è ragionevole che quando cerchi qualcosa che non hai il permesso di vedere (o addirittura sai che esiste), dovresti ottenere un valore nullo.

Se, d'altra parte, non si dispone di una connessione iniziale o di una fase di accesso, un'eccezione ha senso. Se il chiamante sa che esiste un elemento e non lo sta recuperando, l'API non è utile per restituire un valore nullo.

Per creare un oggetto, tuttavia, questa è una storia diversa. Presumibilmente potrebbero esserci molte ragioni per fallire: nessuna autorizzazione, parametri errati, memoria insufficiente del server, ecc. Se allo sviluppatore viene assegnato un valore nullo per tutte queste condizioni, non ha modo di determinare un corretto corso d'azione .

Quindi, per rispondere alla domanda, chiediti qual è la soluzione più utilizzabile dal punto di vista di qualcuno che utilizza il servizio. Può darsi che il modo in cui lo usi sia atipico, e per il caso più comune un null è la risposta giusta.

Quindi, non entrare in una guerra religiosa per questo, decidi cosa è giusto per questo particolare problema.


Non ho intenzione di indossare l'equipaggiamento da battaglia, hehe. Era solo curioso di sapere se avevo completamente torto nel pensare a cosa stavo pensando o no. Voglio imparare, ma non mi piace saltare a qualcosa solo perché una persona lo dice. E soprattutto se non va contro la mia stessa esperienza e logica (non importa quanto piccola). Ad ogni modo, sono totalmente d'accordo sul fatto che se questa fosse un'interfaccia per l'utente finale, allora avrebbe davvero senso. Tuttavia, poiché si tratta di un bean a cui, per quanto ne so, è possibile accedere solo tramite codice, direi che io, come sviluppatore, sono l'utente.
Svish,

1
E come sviluppatore mi importa perché qualcosa non va, indipendentemente da ciò che l'utente finale dovrebbe conoscere.
Svish,

Completamente d'accordo con Bryan. Anche gli sviluppatori sono utenti, vale a dire di consumare del codice di altri sviluppatori. Le descrizioni di lancio o null sono un tipo di interfaccia / interfaccia grafica che dovrebbe essere utile per l'attività specifica. Non solo dal termine generale di logica o filosofia.
Indipendente

3

Sicuramente penso che sia un cattivo design . Null-pointer non è una risposta valida per me e può essere difficile da gestire.

Se l'utente prova a connettere un servizio senza le credenziali appropriate, dovrei rispondere con una risposta chiara e concisa. La risposta potrebbe essere un'eccezione o un oggetto speciale ma non nulla.

È necessario lasciare la risposta nulla in caso di interruzione del collegamento di rete o di altri malfunzionamenti critici imprevisti.

Inoltre, il tempo impiegato a capire perché hai ottenuto un valore nullo è un argomento forte. Qualsiasi parte di codice dovrebbe essere facile da capire e da usare. Avere un valore nullo non è il caso.


Con la tua ultima frase, intendi "Dovresti restituire null solo quando il collegamento di rete è interrotto ecc." o "Dovresti smettere di restituire null quando il collegamento di rete viene interrotto ecc." ?
Péter Török,

@ Péter Török: non consiglio l'uso esplicito di "return null;". Tuttavia, quando si verifica un guasto grave, è accettabile per alcuni servizi restituire null.
Amine,

Un'eccezione non sarebbe più appropriata se si verificasse un guasto critico imprevisto?
Svish,

2
@Amine: direi che è il caso meno appropriato per cui restituire null.
Michael Borgwardt,

@Svish: se riesci a rilevare il guasto principale, ovviamente un'eccezione sarà eccezionale.
Amine,

3

Tenendo presente una buona progettazione del software, dovresti pensare alla vita del tuo progetto.
Restituendo null, come è stato detto, non si fornisce alcuna informazione al cliente. Guarda cosa ti è successo, all'inizio non ti sei reso conto di dove fosse il problema. Inoltre, se non viene fornita alcuna documentazione, questo è un casino.

Lanciando un'eccezione, puoi dire cosa è andato storto. Puoi anche personalizzare il testo visualizzato per essere più specifico se lo desideri.

D'altra parte, ritornando nullfai indurre il cliente a indagare su ciò che sta succedendo.

Inoltre, ti sei reso conto che c'era un problema perché sei arrivato altrove a NullPointerException. Ora immagina di non memorizzare il ritorno di quella funzione ... Sarai costretto a circondare ogni chiamata a quella funzione con un if elseblocco ...

Dal mio punto di vista, il ritorno nullè una cattiva pratica.


2

Lo sviluppatore più esperto che ha scritto il servizio ha sostenuto che la richiesta dei dati non è una condizione di errore e che le eccezioni dovrebbero essere lanciate solo in una condizione di errore, non quando l'utente non ha accesso ai dati.

Dal mio punto di vista, questo non ha senso.

La richiesta di dati senza autorizzazione dovrebbe comportare un'eccezione, poiché si tratta di un risultato imprevisto , per non ottenere alcun risultato, senza un accesso adeguato.

Analogia : il codice di risposta per una GETsenza autorizzazione non è 200 okprivo di dati, in realtà è 401 Unauthorized.


1

Restituire null non è eccezionale. Non ti dice niente. Per fare un esempio, se un'app sta cercando di cercare qualcosa e la risposta è nulla per entrambi i problemi di sicurezza e se l'elemento non esiste, come si fa a distinguere tra i due?

Una risposta significativa può consentire all'applicazione di effettuare scelte logiche su cosa fare in seguito o su come risolvere i problemi.


Ti chiedi come si fa a distinguere la differenza tra un oggetto non presente e non hai il permesso di vederlo. Forse la progettazione del sistema richiede che tu non lo sappia. Non credo che abbiamo abbastanza informazioni per rispondere in questo caso specifico e non esiste una risposta che funzioni in tutti i casi. Ci sono casi d'uso perfettamente validi in cui, se non riesci a vederlo, in realtà non c'è. E ci sono casi d'uso in cui se non riesci a vederlo dovresti ricevere un'eccezione per dire perché non puoi.
Bryan Oakley,

Cosa intendi con "la progettazione del sistema richiede che tu non lo sappia"? Che tipo di design potrebbe essere?
Svish,

2
Se la politica di sicurezza dice che non sei autorizzato a vederlo, nella maggior parte dei casi non dovresti essere in grado di sapere che esiste. Ciò rende il ritorno "non trovato" perfettamente accettabile.
Blrfl,

1

Se la causa principale è un utente non autenticato, preferisco una risposta HTTP 401 rigida, forse con un reindirizzamento a una pagina di messaggi piuttosto (e una notifica a qualcuno che se ne frega). Le cause relative all'autorizzazione sono più caso per caso; ci sono argomenti per la restituzione di errori HTTP (403, diciamo) e argomenti per la restituzione di codici / messaggi speciali ben formati nella risposta del servizio.

Le eccezioni dovrebbero essere utilizzate solo in circostanze eccezionali e significa che qualcosa è andato storto. Non sono d'accordo sul fatto che dovrebbero essere sovraccarichi per significare "non consentito". (Lo stesso vale per il valore di ritorno null: non sono d'accordo sul fatto che dovrebbe essere usato per significare "non consentito".)


Bene, nella GUI potresti farlo, ma per quanto riguarda il bean che implementa il servizio che fa cose dietro le quinte hai solo eccezioni e valori di ritorno speciali a tua disposizione. Ovviamente non intendo che l'utente dovrebbe ottenere l'eccezione, ma l'eccezione potrebbe ad esempio essere catturata nel servizio Web / servlet / qualunque cosa e quindi fare ciò che è appropriato. Reindirizzamento da qualche parte, alla pagina http 4xx o ad altro.
Svish,

Buon punto, ma potresti usare un paradigma come AOP per catturare questi casi. L'Aspetto potrebbe verificare il privilegio di chiamare una determinata operazione e reindirizzare / consentire l'elaborazione per continuare nel modo appropriato.
Segna il

0

Per interpretare l'avvocato dei diavoli cercherò di prendere la parte del ritorno null.

Secondo me esiste solo una situazione in cui questo tipo di risposta è quasi accettabile e cioè, come in questo caso, quando si tratta di sicurezza.

È molto facile fornire accidentalmente dettagli del sistema che le persone non autorizzate non dovrebbero conoscere. Questo dovrebbe essere evitato.

Prendi, ad esempio, un controllo nome utente e password. Restituire un errore "Nome utente non trovato" e un errore "Password errata" come codici di errore separati ti aprirebbero ovviamente a gravi problemi di sicurezza in quanto qualcuno potrebbe prima cercare un nome utente valido e quindi cercare una password. Restituire un "Nome utente / password non validi" generici sarebbe un'opzione migliore.

Pertanto, in questo caso particolare direi che è quasi ok tornare, nullma sono d'accordo, sarebbe molto spiacevole lavorare con.


Sì, non sarei d'accordo. A mio avviso, la risposta corretta sarebbe un'eccezione, ma la stessa sia per il nome utente non trovato che per la password errata. FailedToLogin, InvalidCredentials, qualunque cosa.
Svish,

@Svish - Ma se stai cercando di non dare alcun suggerimento sul motivo del fallimento, il ritorno nullè esattamente la risposta meno utile. Quasi ogni altra cosa potrebbe essere potenzialmente utilizzata per scoprire qualcosa sul sistema. Il motivo per cui l'OP si è lamentato è perché non solo il nullritorno non ha spiegato nulla, ma è stato anche inutile. Questo è l'obiettivo deliberato ... non dire assolutamente nulla ed essere inutile. Missione compiuta dal mio punto di vista.
OldCurmudgeon,

Bene, potrebbe essere così, ma direi comunque che farlo è male. Almeno all'interno di un sistema. Ai margini in cui l'utente finale vede le cose, quindi, posso essere d'accordo. Ma all'interno del sistema, noi sviluppatori siamo gli utenti, e perché nel mondo vorremmo rendere le cose più confuse per noi stessi? Come se lo sviluppo di software non fosse già abbastanza difficile ...
Svish,

1
E con l'esempio di accesso, direi che è male per l'esperienza dell'utente non dire almeno qualcosa sul perché non sembrava accadere nulla quando (credevano di aver inserito) le proprie credenziali. Se la pagina si aggiorna e sembra che abbia semplicemente ignorato il mio tentativo di accedere, presumo che qualcosa non vada nel sistema, non che ciò che ho inserito sia sbagliato.
Svish,

-2

Penso che return null sia ostile, quando il client invoca questo metodo e restituisce null, il client non sa cosa è successo e perché ha restituito null. Quindi dovremmo lanciare l'esecuzione che ha senso e fornire una documentazione per descriverla.

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.