Rückgabe per Referenz = Sicherheitslücke für private Variablen?



  • Hallo zusammen,

    mir ist beim Programmieren mit Referenzen aufgefallen, dass man sich ganz einfach Zugriff zu privaten Variablen verschaffen kann. In dem man sich einfach eine Funktion schreibt, die die Variable als Referenz zurückgibt.
    Ich habe es mal mit einem kleinen Testprogramm verdeutlicht. Meiner Meinung nach verliert man doch dadurch die Sicherheit, dass man die Variablen gezielt(geschützt) über Funktionen verändern kann/darf.

    Nun zum Beispiel:

    #include <iostream>
    using namespace std;
    
    class A
    {
    private:
    	int varA;
    public:
    	A( int a ){ varA = a; }
    
    	int &getA() {
    		return varA;
    	}
    };
    
    int main()
    {
    	A a( 10 );	// Objekt wird erzeugt und mit dem Wert 10 initialisiert
    	// Der Wert der Variable wird ausgegeben
    	cout << "Variable a: " << a.getA() << endl;
    
    	// Nun erzeuge ich mir eine ReferenzVariable und 
    	// gebe eine Referenz der privaten Variable zurück
    	int &b = a.getA();
    
    	// Nun verändere ich einfach den Wert der privaten Variable über die Referenz
    	b = 5;
    	// Und siehe da, der Wert der privaten Variable lässt sich ohne weiteres verändern
    	cout << "Variable a: " << a.getA() << endl;
    
    	return 0;
    }
    

    Ausgabe:
    `

    Variable a: 10

    Variable a: 5

    `

    Damit macht man doch eigentlich das Konzept von geschützen Variablen in Klassen kaputt oder wir seht ihr das? Im Prinzip lässt sich ja so jede geschützte Variable aushebeln und ich bin nicht mehr auf die Methoden der Klasse angewiesen, um die Variable zu verändern. Irgendwie macht mich die Sache einwenig stutzig... 😕



  • Biete eine const-Version der entsprechenden Methode an, nutze const Objekte und biete vor allem nicht Getter für jede einzelne Membervariable an.



  • Ja, du wirst in deiner C++ Laufbahn noch so einiges endecken, das dir komisch vorkommen wird 🙂 Die Sprache bietet dir halt eine enorme Freiheiten.



  • Der einzige Vorteil gegenüber einer public Variable hier ist die Syntax. Wenn du dir dem bewusst bist: Kein Problem. Öffentliche Variablen sind per se nichts schlechtes.

    Der Zwang alles in get/set zu kapseln kommt aus Java und bringt nichts. Selbst die Standardbibliothek aus C++ verwendet public variablen, wenn angemessen.



  • Ja, das mit const ist mir bewusst. Aber es geht rein darum, wenn ich mir sagen, wir mal von jemanden eine Bibliothek borge mit dazugehöriger Header-Datei. Der jenige, der die Bibliothek geschrieben hat, es vorgesehen hat, dass sich die Variablen nur über seine implementierten Funktionen verändern lassen dürfen. Dann schreibe ich mir kurzer Hand eine Funktion die eine Referenz zurück gibt und ich kann dann mit den Variablen machen was ich will, was ja eigentlich nicht im Sinne des Erfinders ist.



  • Du kannst auch einfach private in public ändern, das hat den geleichen Effekt.



  • Wie willst du denn diese Funktion schreiben? Die einzige Möglichkeit ist eine Memberfunktion (oder einen friend) hinzuzufügen, also die Klasse zu verändern. Aber wenn du das kannst, dann kannst du auch das "private" weglöschen.... abgesehen davon, dass das Verhalten undefiniert ist, wenn die Bibliothek nach dieser Änderung nicht neu compiliert wird.

    Noch ein Punkt: Die Sichtbarkeitslevel (private, public, protected) haben nichts mit Sicherheit zu tun, sondern mit der Reduktion von Abhängigkeiten. Das heißt konkret, bestehender Code geht nicht kaputt, wenn sich die privaten Bestandteile einer Klasse ändern, solange die öffentliche Schnittstelle gleich bleibt.



  • sethary schrieb:

    Ja, das mit const ist mir bewusst. Aber es geht rein darum, wenn ich mir sagen, wir mal von jemanden eine Bibliothek borge mit dazugehöriger Header-Datei. Der jenige, der die Bibliothek geschrieben hat, es vorgesehen hat, dass sich die Variablen nur über seine implementierten Funktionen verändern lassen dürfen. Dann schreibe ich mir kurzer Hand eine Funktion die eine Referenz zurück gibt und ich kann dann mit den Variablen machen was ich will, was ja eigentlich nicht im Sinne des Erfinders ist.

    Als ich mit C++ angefangen habe, habe ich mir auch diese Fragen gestellt. Im Laufe der Zeit bekommst du eine andere Sichtweise auf diese Dinge. Nur weil eine Variable privat ist, heißt das nicht das ist super duper geheim und diese muss vor dier geschützt werden. Du wirst immer eine Möglichkeit finden mut-und böswillig deinen Willen in C++ durchzusetzen.

    Dem Library-Entwickler ist das egal, wenn du Blödsinn anstellen möchstest. Das kümmert ihn gar nicht und er kann sich auch gar nicht darum kümmern. Du musst so programmieren, das nicht unabsichtlich fehlerhafte Benutzung durch deine Funktionen und Klassen entstehen. Um böswillige Buben brauchst du dich nicht zu kümmern.



  • Achso, jetzt komm ich der Sache bisschen näher.

    Ihr wollt also damit sagen, dass diese ganzen private/protected/public deklarationen nur dazu da sind, um dem Programmierer, der die Klasse vor sich hat, zu sagen: "Die Variablen sind tabu, die Variablen darfst du so veränder oder die Variablen darfst du komplett vergewaltigen 😃 "
    Ich noch einiges zu lernen haben muss 🤡

    Ok, ich hab die ganze Zeit gedacht, dass diese Angaben in dem Sinne fix sind und man sie eben nicht verändern darf statt sollte.

    @Bashar: Ja, einfach die Funktion in die Klasse implementieren, also ins HeaderFile. Ich mein, dass stört die Library doch nicht oder bin ich da wieder falsch?



  • sethary schrieb:

    @Bashar: Ja, einfach die Funktion in die Klasse implementieren, also ins HeaderFile.

    Na wie jetzt, in die Klasse oder ins Headerfile? Wie gesagt, Zugriff auf private Variablen haben nur (nicht-statische) Memberfunktionen und friends, also Dinge, die in der Klasse selbst deklariert werden. Wenn du dich da einhängen willst, musst du die Klasse verändern.

    Ich mein, dass stört die Library doch nicht oder bin ich da wieder falsch?

    Wenn du das tust, hat die Library eine andere Vorstellung der Klasse als dein Programm. Nach der One-Definition-Rule (Google-Stichwort für dich) müssen alle Definitionen einer Klasse (Token für Token) identisch sein, und das wäre dann nicht mehr gegeben, dein Programm hat also undefiniertes Verhalten.

    Aber wie gesagt, das ganze hat mit Sicherheit sowieso nichts zu tun. Und die Library stört das auch nicht, es stört höchstens dich, spätestens wenn ein nachfolgender Wartungsprogrammierer dich erwürgt.



  • KasF schrieb:

    Dem Library-Entwickler ist das egal, wenn du Blödsinn anstellen möchstest.

    Genau. sethary, du arbeitest mit einer Bibliothek, nicht gegen sie. Wenn du versuchst, das API und die verwendeten Konventionen zu umgehen: Dein Problem. Du schneidest dir ins eigene Fleisch, wenn sich plötzlich die Implementierung ändert und du tagelang Code refactoren musst, weil du "schlauer" warst 😉

    Das Prinzip wird manchmal auch als Murphy vs. Machiavelli bezeichnet. Mechanismen schützen gegen unbeabsichtigte Fehler, nicht gegen bewussten Missbrauch.

    Dazu kommt, dass C++ -- anders als Java z.B. -- sich nicht zum Ziel setzt, den Programmierer zu bevormunden. Du hast so viele Freiheiten wie sonst nirgends, aber dadurch auch eine grosse Verantwortung. Du kannst viel leichter subtile und schwer bemerkbare Fehler machen als in anderen Sprachen. Daher ist es in C++ besonders wichtig, dass man sich genau über seinen Code im Klaren ist und nach den Grundlagen auch Idiome/Richtlinien im Sinne von Effective C++ anschaut.



  • Ich habe auf Channel9 was Interessantes gesehen.

    struct Foo{
    public:
        virtual void f(){}
    };
    
    struct Bar : public Foo{
    private:
        virtual void f(){cout << "private!";}
    };
    
    int main(){
        Foo *fp = new Bar;
        fp->f(); //gibt private aus!
        Bar *bp = new Bar;
        bp->f(); //Error: Bar::f is private
    }
    


  • Bashar schrieb:

    sethary schrieb:

    @Bashar: Ja, einfach die Funktion in die Klasse implementieren, also ins HeaderFile.

    Na wie jetzt, in die Klasse oder ins Headerfile? Wie gesagt, Zugriff auf private Variablen haben nur (nicht-statische) Memberfunktionen und friends, also Dinge, die in der Klasse selbst deklariert werden. Wenn du dich da einhängen willst, musst du die Klasse verändern.

    Da habe ich mich ein bisschen unverständlich ausgedrückt, ja ich meinte die Klasse die in dem HeaderFile implementiert ist.

    Bashar schrieb:

    One-Definition-Rule (Google-Stichwort für dich)

    Danke für den Hinweis, ich werd mich mal darüber ein wenig schlau machen.

    C++ scheint echt sehr komplex und weitläufig in seinen Möglichkeiten zu sein. Was ich mir evetnuell auch gewünschte hätte, wäre vom Compiler eine kurzes Warning, dass ich über eine Referenz versuche auf eine private Variable zu zugreifen, was man eigentlich nicht machen sollte. 😃



  • Vielleicht nochmal zur Klarstellung:

    ein Haufen Header-Dateien mit passenden cpp-Dateien zusammen sind keine Library.

    Eine Library ist eine kompilierte Datei, die mit passenden Header-Dateien geliefert wird. Die Header-Dateien kannst du in deinen Code inkludieren, damit der Compiler weiß, welche Funktionen und Klassen du verwenden willst. Der Linker sucht dann die passenden Elemente in der kompilierten Lib.

    Da zu versuchen, die externen Header zu verändern, ist komplett sinnlos. Du kannst natürlich die Lib komplett neu kompilieren, wenn diese Open Source ist.



  • daddy_felix schrieb:

    Vielleicht nochmal zur Klarstellung:

    ein Haufen Header-Dateien mit passenden cpp-Dateien zusammen sind keine Library.

    Eine Library ist eine kompilierte Datei, die mit passenden Header-Dateien geliefert wird. Die Header-Dateien kannst du in deinen Code inkludieren, damit der Compiler weiß, welche Funktionen und Klassen du verwenden willst. Der Linker sucht dann die passenden Elemente in der kompilierten Lib.

    Da zu versuchen, die externen Header zu verändern, ist komplett sinnlos. Du kannst natürlich die Lib komplett neu kompilieren, wenn diese Open Source ist.

    Das ist mir bewusst, was der Unterschied zwischen den beiden Sachen ist. Jedoch musst ich doch nicht die lib-Datei neu compilieren lassen, wenn ich die komplette Funktion in die Klasse in der HeaderDatei reinpacke und alles andere unberührt lasse.
    Ich will ja nicht, dass dann meine Funktion in der Lib-Datei implementier ist, sondern ich wollte einfach dann über eine Referenz auf die private Elemente zugreifen ohne die vordefinierten Funktionen zu verwenden.

    Aber mittlererweile denk ich, versteh ich das nun mit dem Zugriffschutz.



  • daddy_felix schrieb:

    Da zu versuchen, die externen Header zu verändern, ist komplett sinnlos.

    Wieso? Man kann auf diese Weise auf private-Kram zugreifen.



  • nwp3 schrieb:

    daddy_felix schrieb:

    Da zu versuchen, die externen Header zu verändern, ist komplett sinnlos.

    Wieso? Man kann auf diese Weise auf private-Kram zugreifen.

    echt, das klappt? wieder was gelernt 🙂



  • daddy_felix schrieb:

    ein Haufen Header-Dateien mit passenden cpp-Dateien zusammen sind keine Library.

    Doch. Bibliothek bedeutet im C++-Kontext zwei Dinge:

    • Eine Sammlung von wiederverwendbarer Funktionalität. Ein Open-Source-SDK kann z.B. nur aus .cpp- und .hpp-Dateien bestehen, die dann kompiliert werden. Es gibt auch Header-Only-Bibliotheken, wie der Grossteil von Boost.
    • Eine statische oder dynamische Bibliothek, also kompilierter Code, der zur Link- oder Laufzeit eingebunden werden kann. Typische Dateiendungen sind .lib, .dll, .so.


  • Es gibt auch noch den "tollen Trick":

    #define private public
    #include <header>
    

    Sollte man aber wirklich nur mal zum Testen ausprobieren...



  • Th69 schrieb:

    Es gibt auch noch den "tollen Trick":

    #define private public
    #include <header>
    

    In dem Fall ist die One-Definition-Rule aber sogar mehr als theoretisch, da sich dadurch das Speicherlayout der Klasse ändern kann.


Anmelden zum Antworten