Kann ein Geheimnis in einer "sicheren" Java-Klasse versteckt werden, die Zugangsdaten bietet?

8

Dies ist eine Brainstorming-Frage darüber, was in Java möglich ist (oder nicht). Ich möchte wissen, ob es möglich ist, ein Geheimnis in einer Klasse zu verbergen und den Zugriff darauf zu verhindern mit Java-Code oder nur mit einer Funktion (Sicherheit, Reflexion, Serialisierung, Klassenlader, Sie-Name) -it ...).

Hier ist, was ich bisher gedacht habe:

%Vor%

Kann es verbessert werden? Sollte es verbessert werden? Ist die Idee, ein Geheimnis in einer sicheren Klasse zu sperren, unmöglich zu erreichen?

BEARBEITEN

Relevanz:

Manche Leute hinterfragen die Relevanz des Problems, das ich hier anspreche. Obwohl ich eine allgemeine Frage stelle, um eine offene Konversation auszulösen, gibt es eine sehr konkrete Anwendung für diese Klasse:

  • Wenn ich einige Nachrichten entschlüsseln möchte, muss ich einen privaten Schlüsseldaten in eine Klasse laden. Wenn ich nicht verhindern kann, dass anderer Java-Code darauf zugreift, ist es unmöglich, ein sicheres System zu erstellen. Natürlich, wenn ich eine Nachricht entschlüsseln möchte, sollte ich es lieber in der Klasse machen, als das Geheimnis preiszugeben, aber trotzdem muss der Safe unzerbrechlich bleiben.

Erläuterung:

  • Instanzen der Klasse werden nur zur Laufzeit erstellt, nicht zur Kompilierzeit
  • Code kann in Web-Server-Anwendungen oder beliebigen Desktop- oder Geräteanwendungen ausgeführt werden
  • Die Klasse wird nur verwendet, um ein Geheimnis zur Laufzeit zu speichern, im Speicher gibt es keine Pläne, es zu behalten (für die Persistenz kann / sollte man klassische Verschlüsselungstechniken verwenden)

Fakten:

  • Um die Sicherheit in einer Java-Anwendung zu implementieren, sollte eine SecurityManager-Instanz festgelegt werden, bei der überprüfende Methoden nach Bedarf überschrieben werden.
  • Diese Anwendung kann nicht vertrauenswürdigen Code mit sicheren Klassenladeprogrammen laden und eine Schutzdomäne für die geladenen Klassen zuweisen. Diese Domäne sollte nicht eine RuntimePermission ("setSecurityManager") enthalten.
  • Nicht vertrauenswürdiger Code kann versuchen, den SecurityManager zu ändern, aber da der Secure Class Loader die Berechtigung setSecurityManager nicht erteilt hat, wird eine SecurityException ausgelöst.

Gelöste Probleme:

In Bezug auf die Ausführungsumgebung müssen wir zwei Fälle unterscheiden:

  • Kontrollierte Umgebung: Wir starten die Anwendung, die nicht vertrauenswürdigen Code verwendet, um unser "sicheres" zu brechen.

Wenn wir einen geeigneten SecurityManager einrichten, der die Reflektion deaktiviert und die Berechtigungen für geladenen nicht vertrauenswürdigen Code einschränkt, ist unser Geheimnis sicher.

  • Unkontrollierte Umgebung: Hacker kann die Anwendung starten, die nicht vertrauenswürdigen Code verwendet, um unser 'Safe' zu brechen.

Der Hacker kann seine eigene Anwendung mit einem eigenen Sicherheitsmanager und Secure Class Loader erstellen. Es könnte unseren Code aus dem Klassenpfad laden und ausführen, als wäre es unsere eigene Anwendung. In diesem Fall könnte er den Safe durchbrechen.

JVerstry 23.04.2011, 01:30
quelle

12 Antworten

12

Nein, es ist nicht sicher vor anderem Java-Code. Ihr Geheimnis könnte wie folgt von einer Instanz von Safe abgerufen werden:

%Vor%

Update: Wenn Sie das Laden des anderen Java-Codes steuern, von dem Sie das Geheimnis verbergen möchten, können Sie wahrscheinlich eine benutzerdefinierte SecurityManager oder ClassLoader verwenden, um den Zugriff darauf zu verhindern. Sie müssen jedoch die Umgebung steuern, in der diese ausgeführt wird, z. Ein Server, auf den Sie den Zugriff beschränken.

Ihre bearbeitete Frage erwähnt jedoch, dass der Code auf jedem Desktop oder Gerät ausgeführt werden kann. In diesem Fall gibt es wirklich nichts, was Sie tun können, um das Geheimnis vor anderen Prozessen zu schützen, die alles Mögliche tun können. Selbst wenn Sie es im Speicher verschlüsseln, kann ein anderer Prozess nur den Schlüssel oder sogar das Klartextgeheimnis abfangen, während es weitergeleitet wird.

Wenn Sie die Umgebung nicht kontrollieren, für die Sie etwas Sicheres benötigen, müssen Sie wahrscheinlich einen anderen Ansatz in Betracht ziehen. Vielleicht können Sie es vermeiden, das Geheimnis im Gedächtnis zu speichern?

    
WhiteFang34 23.04.2011, 01:36
quelle
12

Diese "Sicherheit" ist lächerlich.

Wo läuft es? Auf meinem Desktop? Ich verbinde mich mit dem Debugger mit der JVM und zeige alle Geheimnisse im Klartext an.

Oder ich platziere meinen Code daneben und benutze Reflektion, um den Inhalt auszugeben.

Oder ich injiziere meine eigene Code-Modifikation über BCEL und modifiziere den Konstruktor von Safe, um den "geheimen" Wert in eine Datei auszugeben.

Oder ich ersetze einfach das ganze Paket mit meinem mit dem gleichen Namen, indem ich es in den Bootstrap Classloader lege.

Oder ich kann sogar Java-Quellen modifizieren und kompilieren, um eine modifizierte JVM zu erhalten.

Oder ... mein, man kann Dutzende von Möglichkeiten auflisten, um einen Wert aus einer Laufzeit-Instanz zu extrahieren!

Die wahre Frage in jedem Sicherheitsdesign lautet: Wer ist ein Angreifer ? Was ist das Bedrohungsmodell? Ohne dies zu beantworten, ist das Thema sinnlos.

    
Vladimir Dyuzhev 23.04.2011 02:17
quelle
3

Sie können ein Geheimnis "schwer" machen, aber Sie können es nicht unmöglich machen. Es gibt ein Sprichwort (Bruce Schneier glaube ich): Gegen einen gelegentlichen Benutzer funktioniert alles. Gegen einen entschlossenen Cracker funktioniert nichts.

    
seand 23.04.2011 01:57
quelle
1

Ссылка ist eine Objektfähigkeits-Teilmenge von Java, die eine zerlegbare Sicherheit ermöglichen soll - die Fähigkeit Für einen Teil eines Programms, um seine Sicherheitseigenschaften zu erhalten, selbst wenn andere Teile des Programms von einem Angreifer kontrolliert, kompromittiert oder manipuliert werden.

Das heißt, gültige JVMs dürfen die Semantik der Sprache um zusätzliche Sprachfunktionen erweitern, wie zum Beispiel die Möglichkeit, zur Laufzeit einen Debugger anzuhängen. Code, der Runtime zum Aufruf von Shell-Zugriff verwenden kann, kann einen Debugger an viele Bestands-JVMs anhängen und um private Zugriffsbeschränkungen herum arbeiten, selbst wenn die JVM so eingerichtet ist, dass die normale Reflexion das Feld private ness berücksichtigt.

Joe-E verbietet eine Menge des reflexiven Missbrauchs von Informationen, die dies verkomplizieren könnten, und lässt natürlich keinen ungefilterten Zugriff auf Runtime zu.

    
Mike Samuel 23.04.2011 02:25
quelle
1

Ich denke, Sie können das tun, aber Sie drängen das Sicherheitsproblem woanders hin. Gibt es einen Grund, warum "geheim" nicht verschlüsselt werden kann, indem Sie (aus Gründen der Einfachheit) Ihren bevorzugten symmetrischen Schlüsselalgorithmus verwenden? Die gimmeTheSecret () - Methode müsste einen zusätzlichen Parameter annehmen, der den geheimen Schlüssel verwendet, um das Geheimnis zu entschlüsseln.

Natürlich besteht dann das Problem, dass dieser geheime Schlüssel von einem Benutzer oder einer Maschine, die ihn irgendwo sicher speichert, bekannt sein und eingegeben werden muss. Sie könnten eine Art Hardware-Sicherheitsmodul verwenden, abhängig davon, wie sensibel die Daten sind und wie viel Sie ausgeben möchten!

    
alpian 27.04.2011 18:18
quelle
1
  

Manche Leute stellen die Relevanz von   das Thema, das ich hier aufwerfe. Obwohl   Ich stelle eine allgemeine Frage in   Um eine offene Konversation auszulösen,   Es gibt eine sehr konkrete Anwendung   zu dieser Klasse:

     

Wenn ich einige Nachrichten entschlüsseln möchte, ich   müssen einen privaten Schlüsseldaten in einen laden   Klasse. Wenn ich andere Java nicht verhindern kann   Code vom Zugriff darauf, dann ist es   unmöglich, ein sicheres System zu erstellen.   Natürlich, wenn ich eine entschlüsseln möchte   Nachricht, ich sollte es lieber in der tun   Klasse als das Geheimnis zu verraten, aber   trotzdem muss der Safe bleiben   unzerbrechlich.

Erstens in Sicherheit, unknackbar gibt es nicht. Es gibt eine winzige Chance, dass ich zufälligerweise den Schlüssel für die Beschreibung finde, indem ich zufällige Dinge auf meiner Tastatur schreibe. Wenn Ihr Schlüssel komplex ist, würde Sie ein wirklich unglücklicher Mann machen, aber das ist möglich.

Der zweite Punkt, der ein öffentliches / privates Schlüssel-Wert-Paar verwendet, um die Kommunikation zwischen einem Client und einem Server zu schützen, ist wirklich üblich und funktioniert perfekt, wenn es richtig gemacht wird. Aber man muss verstehen, dass dies wirklich die Kommunikation zwischen den beiden Computern schützt. Es schützt den Computer nicht selbst. Die ganze Sache basiert auf totalem Vertrauen, das der Computer von einander hat.

Dritter Punkt, wenn Sie physischen Zugriff auf einen Computer haben, können Sie damit alles machen, was Sie wollen, insbesondere das Spionieren von allem, was ein Programm macht. Und alle Inhalte des Computers. Der Inhalt kann ja verschlüsselt werden, aber während der Verwendung wird er nicht mehr verschlüsselt. Dies ist ein großes Problem des öffentlichen / privaten Schlüsselsystems: Der private Schlüssel wird irgendwo gespeichert, so dass Sie sicher sein müssen, dass dieser Ort sicher ist.

Dieser Ablauf kann für Sie vollkommen akzeptabel sein, wenn Sie den an der Kommunikation beteiligten Computern vertrauen. Dies ist beispielsweise der Fall, wenn Sie eine Verbindung zu Ihrem Bankkonto herstellen.

Bank-Computer werden von der Bank als vertrauenswürdig eingestuft, und der bereitgestellte Zugriff auf externe Wörter ist wirklich eingeschränkt und kontrolliert. Sie sind "sicher".

Wenn Sie Ihren eigenen privaten Schlüssel oder Anmeldeinformationen an die Bank weitergeben. Sie sind kompromittiert, aber es ist Ihre Verantwortung und Ihr Problem. Da es nicht in Ihrem Interesse ist, kompromittiert zu werden, werden Sie Ihr Bestes tun, um dies zu vermeiden. Das ist nett, weil du derjenige bist, der die volle Kontrolle über deinen Computer hat.

Aber sagen wir, Sie greifen von einem öffentlichen Computer oder einem Computer von einer anderen Person auf Ihre Bank zu. Dann kann ein einfacher Keylogger nur die Tasten und die Mausbewegung aufzeichnen, die Sie machen, wenn Sie Ihr Passwort eingeben.

Die Sicherheit auf Client-Seite basiert auf Vertrauen, das Sie auf dem Client haben können. Wenn Sie ihm vertrauen können, ist das perfekt, es funktioniert. Wenn Sie nicht können, dann ist es kaputt.

    
Nicolas Bousquet 30.04.2011 14:45
quelle
1

Wenn Sie nicht vertrauenswürdigen Code ausführen müssen, führen Sie dies am besten in einer separaten JVM aus. Auf diese Weise kann dem nicht vertrauenswürdigen Code die strengsten Beschränkungen auferlegt werden und sogar getötet werden, wenn Sie zum Beispiel eine ausgelaufene CPU haben oder die JVM zum Absturz bringen. Der einzige Zugriff, den der Code machen kann, ist über die Mittel, die Sie ihm zur Verfügung stellen. Eine Reflektion wird Ihnen keinen Zugriff auf Klassen in einer anderen JVM geben, egal was Sie tun.

Sie können sogar ein Gefängnis oder Labyrinth für Ihre Anwendung erstellen. Dadurch kann der nicht vertrauenswürdige Code in einem scheinbar echten System ausgeführt werden, in Wirklichkeit jedoch nicht. (Der Zweck davon ist, dich zu binden, wäre ein Hacker lang genug, um zu sehen, was sie tun)

Sie könnten sogar die JVM in ihrer eigenen virtuellen Maschine laufen lassen, so dass es aussieht, als ob Sie ein vollständiges (aber dummes) System haben, um "einzudringen". Eine virtuelle Maschine kann zur Analyse gespeichert und sehr einfach in einen voreingestellten Zustand gewischt werden.

Die ultimative Lösung besteht darin, den nicht vertrauenswürdigen Code in einem eigenen Dummy-LAN zu platzieren. (Etwas, was sie getan haben, um den Stuxnet-Wurm zu analysieren.;)

    
Peter Lawrey 01.05.2011 09:56
quelle
0

Nein, du kannst ein Geheimnis nicht so in eine Klasse einbetten. Wenn Sie das kompiliert haben, dann könnte ich einfach strings auf die resultierende Klassendatei ausführen und es könnte dort drin sein.

Eine Möglichkeit, wie Sie das machen können, wenn Sie nur versuchen, es zu validieren, besteht darin, einen Hash darin zu speichern. Sobald Sie die Eingabe validieren möchten, hacken Sie diese und vergleichen Sie die Hashes.

    
icktoofay 23.04.2011 01:33
quelle
0

Sie können es aus der .class-Datei mit Hilfe von Proguard oder ähnlichen Tools verschleiern. Sie können Ihr JAR auch signieren, damit andere Pakete nicht darauf zugreifen können. Das Signieren Ihrer JAR kann auch helfen.

    
Vicente Plata 23.04.2011 01:39
quelle
0

Angenommen, Informationen, die an Methodenaufrufe übergeben werden, sind sicher, ein Schlüssel ist eine gute Lösung. Der Schlüssel muss nicht irgendwo in der App gespeichert werden. Aus diesem Grund kann auf die Informationen nicht nur über Java zugegriffen werden. Es wird interessant, wenn Sie eine Möglichkeit haben wollen, das Geheimnis mit anderen zu teilen, ohne ihnen Ihren Schlüssel zu geben, wofür die shareSecret Methode unten steht. Es wird jedoch schwierig, dies zu verwalten. Ein Prozess könnte sein:

1) Der geheime Sucher beantragt den Zugriff und gibt einen temporären Schlüssel ein, der gespeichert ist

2) Der geheime Keeper gewährt Zugriff mit seinem Schlüssel, der temporäre Schlüssel wird gelöscht und ein temporäres sicheres Objekt wird erstellt, das für den temporären Schlüssel funktioniert.

3) Der geheime Sucher gibt den temporären Schlüssel und einen permanenten Schlüssel ein, das temporäre sichere Objekt wird gelöscht und ein neues dauerhaftes sicheres Objekt wird erstellt, auf das mit dem permanenten Schlüssel zugegriffen werden kann.

Auch wenn angenommen wird, dass an Methodenaufrufe übergebene Parameter sicher sind, besteht das Hauptproblem der obigen Prozedur darin, dass jemand den temporären Schlüssel zwischen 1 und 2 entführt haben könnte, um das temporäre Geheimnis zwischen den Schritten 2 und 3 zu sehen. es würde es schwerer machen zu knacken, als es in einer Klartextkette zu speichern.

%Vor%     
Briguy37 28.04.2011 03:10
quelle
0

Es gibt einen anderen Aspekt für dieses Problem: Java hat Berechtigungen geliefert. In einem Kontext, in dem die Umgebung kontrolliert wird, kann man den Klassen, die mit einem sicheren Klassenlader geladen sind, einen Satz von Berechtigungen zuweisen.

Java liefert drei Berechtigungsobjekte für die Implementierung der Sicherheit:

  

PrivateCredentialPermission SecurityPermission AuthPermission

Diese können dazu beitragen, den Zugriff auf Funktionalitäten bei der Implementierung eines Kryptographiesystems zu verbessern und zu kontrollieren. Sie sind notwendigerweise ausreichend, um das System zu sichern.

    
JVerstry 30.04.2011 16:00
quelle
0

Einen Kommentar für jeden anderen hinzufügen, der über diesen alten Thread stolpert ....

Manchmal brauchen Sie nur einen 'signierten' Wert, keinen 'verschlüsselten' Wert. Zum Beispiel müssen (codierte) Lizenz-Tokens signiert werden, sie sollten jedoch nicht verschlüsselt werden müssen. In diesen Fällen können Sie den PUBLIC-Schlüssel verteilen, und es ist kein Problem, dass irgendjemand es sehen kann. Sie sind immer noch geschützt, da niemand das signierte Token erstellen kann.

Sie können den öffentlichen Schlüssel auch verwenden, um verschlüsselte Nachrichten an den Server zu senden.

Natürlich wird dies einen kenntnisreichen und entschlossenen Angreifer nicht aufhalten - siehe die anderen Antworten. In diesem Fall könnte jemand Ihren öffentlichen Schlüssel einfach durch einen eigenen ersetzen. wenn Sie die Cert-Kette nicht validieren. Aber wenn Sie statt der Verschlüsselung Signaturen verwenden können, ersparen Sie sich große Kopfschmerzen.

    
bgiles 09.10.2013 16:22
quelle

Tags und Links