Sind private Methoden wirklich sicher?

92

In Java gilt der privateZugriffsmodifikator als sicher, da er außerhalb der Klasse nicht sichtbar ist. Dann weiß die Außenwelt auch nichts über diese Methode.

Aber ich dachte, Java Reflection kann diese Regel brechen. Betrachten Sie folgenden Fall:

public class ProtectedPrivacy{

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

}  

Jetzt werde ich von einer anderen Klasse Info bekommen:

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 diesem Moment dachte ich nur, dass private Methoden noch sicher sind, da wir den Methodennamen kennen müssen, um etwas wie oben zu tun. Aber wenn Klassen, die private Methoden enthalten, die von jemand anderem geschrieben wurden, haben wir keine Sichtbarkeit dieser.

Aber mein Punkt wird ungültig, da unter der Codezeile.

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

Dies method[]enthält nun alle Dinge, die oben zu tun sind. Meine Frage ist, gibt es eine Möglichkeit, solche Dinge mit Java Reflection zu vermeiden?

Ich zitiere einen Punkt aus der Java-Dokumentation , um meine Frage zu klären.

Tipps zur Auswahl einer Zugriffsebene:

Wenn andere Programmierer Ihre Klasse verwenden, möchten Sie sicherstellen, dass keine Fehler durch Missbrauch auftreten können. Zugriffsebenen können Ihnen dabei helfen. Verwenden Sie die restriktivste Zugriffsebene, die für ein bestimmtes Mitglied sinnvoll ist. Verwenden Sie privat, es sei denn, Sie haben einen guten Grund, dies nicht zu tun.

Ruchira Gayan Ranaweera
quelle
1
Die Verwendung eines Obfuscators kann hilfreich sein, da getDeclaredMethodsNamen zurückgegeben werden, die wie Müll aussehen.
Dasblinkenlight
213
Private, geschützte öffentliche Einrichtungen usw. dienen nicht der Sicherheit, sondern vermeiden, dass gut gemeinte Personen Fehler machen. Verwenden Sie es nicht als Sicherheitsmaßnahme
Richard Tingle
20
Java-Code ist sowieso dekompilierbar. Ein "Angreifer" könnte einfach einen Java-Dekompiler herunterladen und Ihren Code lesen oder "privat" in "öffentlich" ändern.
11684
7
Um herauszufinden, was @RichardTingle kommentiert hat (+1 übrigens). Es gibt einen großen und wichtigen Unterschied zwischen Sicherheit und Schutz. Wo letzteres das Problem ist, das mit Zugriffsmodifikatoren gemildert wird; bricht die Dinge nicht durch Zufall
Benutzer
3
All dies ist Programmierern ziemlich klar, bei denen keine Zugriffsmodifikatoren vorhanden sind, wie in Python. In diesen Sprachen werden privat / öffentlich einfach durch eine Konvention in den Namen unterschieden (in Python sollte alles, was mit einem einzelnen Unterstrich beginnt, als privat betrachtet werden). Dies macht es , dass ziemlich klar Kennzeichnung etwas als „privat“ ist nicht jede Sicherheit hinzufügen, aber es ist nur eine einfache Art und Weise zu sagen , was die Leute sollten Ihren API verwenden. Ich habe meine Zweifel, dass ein Compiler-Check für diese Dinge überhaupt hilft, da es verdammt einfach ist, die Konvention ohne "externe" Hilfe zu befolgen.
Bakuriu

Antworten:

95

Es kommt darauf an, was Sie unter "sicher" verstehen. Wenn Sie mit einem Sicherheitsmanager arbeiten, der solche Dinge zulässt, können Sie alle möglichen bösen Dinge mit Reflexion tun. Aber in einer solchen Umgebung kann die Bibliothek wahrscheinlich nur geändert werden, um die Methode trotzdem öffentlich zu machen.

Die Zugriffskontrolle ist in einer solchen Umgebung effektiv "beratend" - Sie vertrauen effektiv darauf, dass der Code gut funktioniert. Wenn Sie dem von Ihnen ausgeführten Code nicht vertrauen, sollten Sie einen restriktiveren Sicherheitsmanager verwenden.

Jon Skeet
quelle
3
Tangential, ich weiß, aber könnten Sie etwas näher darauf eingehen, was ein restriktiverer Manager in diesem Sinne wäre?
Grau
12
@Gray: Eine Instanz von SecurityManager, die im check*Grunde genommen Ausnahmen für die relevanten Aufrufe auslöst .
Jon Skeet
40

Zugriffsmodifikatoren haben nichts mit Sicherheit zu tun. Tatsächlich können und sollten Sie Zugriffsmodifikatoren als Umkehrung der Sicherheit betrachten - es geht nicht darum, Ihre Daten oder Algorithmen zu schützen, sondern um Menschen vor der Anforderung zu schützen, über Ihre Daten und Algorithmen Bescheid zu wissen. Aus diesem Grund ist der Standardmodifikator package - wenn sie an dem Paket arbeiten, müssen sie es wahrscheinlich bereits wissen.

Zusammen mit der Kenntnis der Daten und der Methoden Ihres Codes kommt die Verantwortung, zu wissen, wann und wie Sie sie verwenden. Sie setzen Ihre inIt-Methode nicht privat, um jemanden davon abzuhalten, davon zu erfahren. Sie tun dies, weil (a) er nicht weiß, dass Sie das nur nach foo aufrufen und nur, wenn bar = 3.1415 und (b) weil es ihnen nicht gut tut, davon zu wissen.

Zugriffsmodifikatoren können in einem einfachen Satz zusammengefasst werden: "TMI, Alter, das musste ich also nicht wissen".

jmoreno
quelle
3
Tolle Antwort, aber ich musste googeln, um herauszufinden, dass TMI zu viele Informationen bedeutet. Ich denke, ich muss mehr Zeit im Tal verbringen :-)
Mikelong
7

Wenn Sie "sicher" sagen, schützen Sie sich oder andere Entwickler, die Ihre API verwenden, um das Objekt nicht zu beschädigen, indem Sie Ihre private Methode aufrufen. Aber wenn Sie oder sie diese Methode wirklich aufrufen müssen, können sie dies mit Reflection tun.

Arsen Alexanyan
quelle
6

Die Frage ist, vor wem Sie es retten wollen. Meiner Meinung nach ist ein solcher Client Ihres Codes hier derjenige, der hier ratlos ist.

Jeder Code (von Ihnen oder anderen geschrieben), der versucht, auf ein privateMitglied der oben genannten Klasse zuzugreifen, gräbt im Wesentlichen sein eigenes Grab. privateMitglieder machen keinen Teil der öffentlichen API und können ohne vorherige Ankündigung geändert werden. Wenn ein Client eines dieser privaten Mitglieder auf die oben angegebene Weise verwendet, wird es unterbrochen, wenn er auf eine neuere Version der API aktualisiert, in der das private Mitglied geändert wurde.

hthserhs
quelle
5

Mit der Einrichtung geht Verantwortung einher. Es gibt Dinge, die Sie nicht tun können, und Dinge, die Sie tun können, die Sie aber nicht tun sollten.

Der private Modifikator wird als / auf die am meisten eingeschränkte Weise bereitgestellt / verwendet. Mitglieder, die außerhalb der Klasse nicht sichtbar sein sollten, werden als privat definiert. Aber dies kann mit Reflection gebrochen werden, wie wir sehen. Dies bedeutet jedoch nicht, dass Sie nicht privat verwenden sollten - oder sie sind unsicher. Es geht darum, dass Sie die Dinge vernünftig oder konstruktiv einsetzen (wie Reflexion).

Raúl
quelle
5

Angenommen, Sie vertrauen dem Client-Programmierer Ihrer API, besteht eine andere Sichtweise darin, wie sicher es für ihn ist, diese bestimmten Funktionen zu verwenden.

Ihre öffentlich verfügbaren Funktionen sollten eine klare, gut dokumentierte und sich selten ändernde Schnittstelle zu Ihrem Code bieten. Ihre privaten Funktionen können als Implementierungsdetail betrachtet werden und können sich im Laufe der Zeit ändern. Sie können daher nicht direkt verwendet werden.

Wenn ein Client-Programmierer sich Mühe gibt, diese Abstraktionen zu umgehen, erklärt er in gewisser Weise, dass er weiß, was er tut. Noch wichtiger ist, dass sie verstehen, dass es nicht unterstützt wird und möglicherweise nicht mehr mit zukünftigen Versionen Ihres Codes funktioniert.

robbie_c
quelle
5

privatedient nicht der Sicherheit, sondern dient dazu, den Code sauber zu halten und Fehler zu vermeiden. Benutzer können den Code modularisieren (und wie er entwickelt wird), ohne sich um alles kümmern zu müssen Details der anderen Module

Sobald Sie Ihren Code veröffentlicht haben, können die Benutzer herausfinden, wie er funktioniert. Es gibt keine Möglichkeit, die Logik zu "verbergen", wenn der Code schließlich auf einem Computer ausgeführt werden soll. Sogar das Kompilieren in Binärdateien ist nur eine Verschleierungsstufe.

Es gibt also keine Möglichkeit, Ihre API so einzurichten, dass bestimmte Dinge ausgeführt werden, die andere nicht aufrufen können. Im Fall einer Web-API können Sie die Methoden, über die Sie die Kontrolle haben möchten, auf die Serverseite stellen.

Manishearth
quelle