I metodi privati ​​sono davvero sicuri?


92

In Java il privatemodificatore di accesso è considerato sicuro poiché non è visibile all'esterno della classe. Allora anche il mondo esterno non conosce quel metodo.

Ma ho pensato che la riflessione Java possa essere utilizzata per infrangere questa regola. Considera il seguente caso:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

Ora da un'altra classe riceverò informazioni:

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

In questo momento ho pensato che il metodo privato fosse ancora sicuro poiché per fare qualcosa come sopra dobbiamo conoscere il nome del metodo. Ma se una classe che contiene un metodo privato scritto da qualcun altro non ne abbiamo visibilità.

Ma il mio punto diventa non valido poiché sotto la riga di codice.

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

Ora questo method[]contiene tutte le cose che devi fare sopra. La mia domanda è: c'è un modo per evitare questo tipo di cose usando la riflessione Java?

Cito un punto della documentazione Java per chiarire la mia domanda.

Suggerimenti per la scelta di un livello di accesso:

Se altri programmatori usano la tua classe, vuoi assicurarti che non si verifichino errori da un uso improprio. I livelli di accesso possono aiutarti a farlo: utilizza il livello di accesso più restrittivo che abbia senso per un determinato membro. Usa privato a meno che tu non abbia una buona ragione per non farlo.


1
L'uso di un offuscatore può aiutare, perché getDeclaredMethodsrestituirebbe nomi che sembrano spazzatura.
dasblinkenlight

213
Privato, pubblico protetto, ecc. Non è per la sicurezza, è per evitare che le persone ben intenzionate commettano errori. Non usarlo come misura di sicurezza
Richard Tingle

20
Il codice Java è comunque decompilabile. Un "aggressore" potrebbe semplicemente scaricare un decompilatore Java e leggere il tuo codice, oppure cambiare "privato" in "pubblico".
11684

7
Per elaborare ciò che ha commentato @RichardTingle (+1 btw). C'è una differenza grande e importante tra sicurezza e protezione. Dove quest'ultimo è il problema mitigato con modificatori di accesso; per non rompere le cose per sbaglio
utente

3
Tutto questo è abbastanza chiaro per i programmatori in cui non esistono modificatori di accesso, come in Python. In questi linguaggi privato / pubblico sono distinti semplicemente da una convenzione nei nomi (in python tutto ciò che inizia con un singolo trattino basso dovrebbe essere considerato privato). Questo rende abbastanza chiaro che contrassegnare qualcosa come "privato" non aggiunge alcuna sicurezza, ma è solo un modo semplice per dire cosa le persone dovrebbero usare della tua API. Ho i miei dubbi sul fatto che avere un controllo del compilatore per queste cose sia di aiuto poiché è dannatamente facile seguire la convenzione senza un aiuto "esterno".
Bakuriu

Risposte:


95

Dipende da cosa intendi per "sicuro". Se stai correndo con un gestore della sicurezza che consente questo genere di cose, allora sì, puoi fare tutti i tipi di cose brutte con la riflessione. Ma poi in quel tipo di ambiente la libreria può probabilmente essere modificata per rendere comunque pubblico il metodo.

Il controllo degli accessi è effettivamente "consultivo" in un ambiente come quello: ti stai effettivamente fidando che il codice funzioni bene. Se non ti fidi del codice che stai eseguendo, dovresti utilizzare un gestore della sicurezza più restrittivo.


3
Tangenziale, lo so, ma potresti approfondire un po 'cosa sarebbe un manager più restrittivo in questo senso?
Gray

12
@Gray: un'istanza di SecurityManager che genera eccezioni sulle check*chiamate pertinenti , fondamentalmente.
Jon Skeet

40

I modificatori di accesso non hanno nulla a che fare con la sicurezza. In effetti, puoi e dovresti considerare i modificatori di accesso come il contrario della sicurezza: non è per proteggere i tuoi dati o algoritmi, ma per proteggere le persone dall'obbligo di conoscere i tuoi dati e algoritmi. Questo è il motivo per cui il modificatore predefinito è pacchetto: se stanno lavorando sul pacchetto probabilmente hanno già bisogno di saperlo.

Insieme alla conoscenza dei dati e dei metodi del tuo codice, arriva la responsabilità di sapere quando e come usarlo. Non metti privato sul tuo metodo inIt per impedire a qualcuno di scoprirlo, lo fai perché (a) non sapranno che lo chiami solo dopo foo e solo se bar = 3.1415 e (b) perché non fa loro bene saperlo.

Modifers accesso possono riassumere in una semplice frase "TMI, amico, io quindi non ho bisogno di sapere che".


3
Ottima risposta, ma avevo bisogno di google per scoprire che TMI significava troppe informazioni. Immagino di dover passare più tempo nella valle :-)
mikelong

7

Dicendo "sicuro", stai proteggendo te o altri sviluppatori, che utilizzano la tua API per non danneggiare l'oggetto chiamando il tuo metodo privato. Ma se tu o loro avete davvero bisogno di chiamare questo metodo, possono farlo con Reflection.


6

La domanda è da chi stai cercando di salvarlo . Secondo me, un tale client del tuo codice è quello in perdita qui.

Qualsiasi pezzo di codice (scritto da te o da altri) che cerca di accedere a un privatemembro della classe precedente sta essenzialmente scavando la propria fossa. privatei membri non fanno parte dell'API pubblica e sono soggetti a modifiche senza preavviso. Se un client utilizza uno di tali membri privati ​​nel modo sopra indicato, si interromperà se si aggiorna a una versione più recente dell'API in cui il membro privato è stato modificato.


5

Con la facilità, arriva la responsabilità. Ci sono cose che non puoi fare e cose che puoi fare ma che non dovresti fare.

Il modificatore privato viene fornito / utilizzato come / nel modo più limitato. I membri che non dovrebbero essere visibili al di fuori della classe devono essere definiti come privati. Ma questo può essere rotto con la Riflessione come vediamo. Ma questo non significa che non dovresti usare private - o non sono sicuri. Si tratta di usare le cose con giudizio o in modo costruttivo (come la riflessione).


5

Supponendo che ti fidi del programmatore client della tua API, un altro modo di vedere quanto sia "sicuro" per loro utilizzare quelle particolari funzioni.

Le tue funzioni disponibili pubblicamente dovrebbero fornire un'interfaccia chiara, ben documentata e che cambia raramente nel tuo codice. Le tue funzioni private possono essere considerate un dettaglio di implementazione e possono cambiare nel tempo, quindi non sono sicure da usare direttamente.

Se un programmatore cliente fa di tutto per aggirare queste astrazioni, in un certo senso dichiara di sapere cosa sta facendo. Ancora più importante, capiscono che non è supportato e potrebbero smettere di funzionare con le versioni future del codice.


5

privatenon è per la sicurezza, è per mantenere il codice pulito e per evitare errori. Consente agli utenti di modularizzare il codice (e come viene sviluppato) senza doversi preoccupare di tutti i dettagli degli altri moduli

Una volta rilasciato il codice, le persone possono capire come funziona. Non c'è modo di "nascondere" la logica se alla fine si desidera che il codice venga eseguito su un computer. Anche la compilazione in formato binario è solo un livello di offuscamento.

Quindi, non è possibile impostare la tua API per fare cose speciali che non vuoi che altri possano chiamare. Nel caso di un'API web, puoi mettere i metodi su cui vuoi controllare sul lato server.

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.