C++ Sicher programmieren
-
Fast jedes UB ist ein Sicherheitsrisiko (z.B. Zugriff außerhalb von Array/Speichergrenzen).
Kommen wir zum Thema zurueck: Und das ist jetzt C++ spezifisch?

Und btw. Zugriff auf Arrays oder Tupels kann auch mathematisch ausgedrueckt werden, nennt sich Projektion in der Informatik.
-
Nein, da hast du Unrecht. Knivil hat schon einen guten Vergleich gebracht.
Der Standard sagt zu manchen Dingen(die entweder fehlerbehaftet sind oder sehr leicht Fehelr erzeugen), dass das verhalten undefiniert ist. D.h. es kann passieren was will. Die Compilerhersteller können da reagieren wie sie wollen. Um es mal sinngemäß zu rezitieren:
Und UB kann eben zu Sicherheitslöchern führen, aber nichts zwangsweise:
void f(int, int); void g(int i, int* v) { i = v[i++]; // the behavior is undefined i = 7, i++, i++; // i becomes 9 i = i++ + 1; // the behavior is undefined i = i + 1; // the value of i is incremented f(i = -1, i = -1); // the behavior is undefined }(§1.9.15)
-
Der Punkt ist: Programme mit undefiniertem Verhalten sind wie falsche Beweise. Der Fehler liegt beim Schreiber und nicht in der verwendeten Sprache. Sie sind einfach falsch. Und ich kann mindestens genausoviele falsche Programme in Java schreiben, wie in C++. Trotzdem halte ich eine Diskussion ueber falsche Programme fuer reichlich sinnlos.
-
knivil schrieb:
Der Punkt ist
Der wirkliche Punkt ist: In C++ ist es viel einfacher, falsche Programme zu schreiben. Klar kannst du sagen, der Fehler liegt beim Programmierer, aber da in der Realität die wenigsten Leute gut C++ können, ist Java im Bezug auf Sicherheit geeigneter.
-
knivil schrieb:
Der Punkt ist: Programme mit undefiniertem Verhalten sind wie falsche Beweise. Der Fehler liegt beim Schreiber und nicht in der verwendeten Sprache. Sie sind einfach falsch. Und ich kann mindestens genausoviele falsche Programme in Java schreiben, wie in C++.
Das ist eine dumme Milchmädchenrechnung. Laut deiner Logik ist es genauso sicher in einem Auto ohne Airbag und Sicherheitsgurt zu fahren wie in einem Auto mit Airbag und Sicherheitsgurt zu fahren, weil es 1000 andere Möglichkeiten zum sterben gibt.
Aber was soll in einem C++ Forum auch anderes rauskommen, als das C++ super Sicher ist.
-
Jain, klar C++ ist in der Hinsicht schwerer. Aber im Umkehrschlsus dafür dann doch sicherer, wenn die Programme sicher geschrieben sind.
In Java ist dann nochmal alles von der JVM und der Version und und und abhängig.
Guckt man sich irgendwelche News-Ticker an, kommt alle Naselang mal "Java Sicherheitsloch entdeckt/gefixt". Andererseits kommt eher weniger sowas wie "C Runtime Environment ist fehlerhaft".In C/C++ passiert nur das, was du willst. Und das hat seine Vor- und Nachteile.
-
[quote="sry"]
knivil schrieb:
Aber was soll in einem C++ Forum auch anderes rauskommen, als das C++ super Sicher ist.
Und Java soll sicherer sein? Ich möchte in keinem Auto/Flugzeug/Atomkraftwerk, Aufzug sitzen in dem statt einer Notfallreaktion erst noch schnell eine Garbage-Collection gemacht werden muss

Bei irgendwelchen Internetprogrämmchen ist so etwas egal.
In sicherheitskritischen Systemen finden die Spielzeugsprachen Java und C# nicht statt.
-
Nicht alles, was hinkt, ist auch ein Vergleich.
Und mir geht es eher hierdrum:
sry schrieb:
knivil schrieb:
Deswegen gibt es keine C, C++ oder Java spezifischen Fehler.
So ein Quatsch.
-
Officer schrieb:
Was kann man in einem C++ Programm noch falsch machen, wenn man modernes C++ verwendet, damit man eine Sicherheitslücke in seinem Programm(Server/Forensoftware) hat? Wenn man std::vector und std::string statt normaler Arrays verwendet und keine Pointeroperationen macht und immer Smartpointer/RAII verwendet, kann man dann noch viel falsch machen?
Wenn du schlaue Zeiger mit rohen Zeigern mischt (was durchaus sinnvoll sein kann), könntest du versehentlich ein Objekt zu früh löschen. Das muss man vom Design her auch schon ausschließen können. Beispielsweise könnte man einen bidirektional-verdrahteten binären Suchbaum so bauen:
struct node { node* parent; unique_ptr<node> left, right; … };oder auch so:
struct node { node *parent, *left, *right; … }; class tree { public: … private: boost::ptr_vector<node> nodes_; node *root; … };Hauptsache, der/die Besitzer stirbt/sterben als letzte(r), die noch einen Zeiger auf so ein node-Objekt haben.
Und sonst gibt's ja noch so einiges mit UB. Die ganzen Überprüfungen, die in anderen Sprachen garantiert werden, gibt's in C++ nicht. Du kannst natürlich auch mit Iteratoren noch Blödsinn machen. Mit einem Vektor-Iterator kannst du ggf über das Ende hinauslaufen etc. Die Debug-Modi mit ihren Extre-Checks (safe iterators etc) helfen während der Entwicklung. Im Release-Modus fährst du dann ohne Stützräder.
-
Klar, sowas wie Codeinjection geht ja immer noch.
Kleine Aufgabe dazu:
C++:int main() { cout << "Gib einen Befehl ein: "; string command; getline(cin, command); return system(command.c_str()); }Ist dieses Programm sicher?
Was ist damit alles möglich?
Wo sind Fehler?
Gibt es Programmierer-Bugs?Was kann den hier passieren außer dass man bei einer gewissen Größe (2^16 Zeichen?) die Kommandozeile zum Überlauf bringen würde?
-
Du kannst JEDEN befehl in das Programm einspeisen und somit mit dem Rechner machen was du willst.
Stell dir mal vor du bist der (böse) User, sitzt an dem Rechner, aber hast keine Adminrechte, kannst demnach nichts kaputtmachen (nehmen wir mal an). Jeetzt startet das Programm aber im Adminmodus (weil es diese Rechte an anderer Stelle braucht und auch so eignerichtet ist, ok) und du bekommst somit als eigentlich nicht berechtigter User die volle Kontrolle über den Rechner und kannst ihn kaputtmachen.
Der Fehler liegt erstens darin system zu nutzen
und zweitens darin, eigegebene Daten ohne Prüfung weiter zu geben und darauf aufzubauen.Nächstes Beispiel:
int main() { char buf[100]; cin.getline(buf, 100); return 0; }Was ist damit?
Was kann passieren?
Wo liegt der Fehler?
-
Das ist aber grenzwertig ob das überhaupt ein Fehler ist. Jeden Befehl mit Adminrechten ausführen zu können kann auch ein Feature sein, man denke an ein Programm für Remote-Login, wo der Nutzer womöglich sogar ein Admin ist.
Ich will auch mal ein Programm in den Raum werfen: format. Formatiert einen Datenträger. Ist das Programm gefährlich? Nützlich? Das hat mit C++ und allgemein Programmierung überhaupt nichts mehr zu tun.
-
Aber sowas sind Sicherheitslücken.
Wenn hier einer von den Webprogrammierern ist, die können da auch en Lied von singen. So SQL-Injections und sowas...
Letztlich gehört das aber alles zum sauberen Programmieren und Software-Designen dazu.
-
Nächstes Beispiel:
int main() { char buf[100]; cin.getline(buf, 100); return 0; }Was ist damit?
Was kann passieren?
Wo liegt der Fehler?Keine Ahnung. Kann es sein das buf nicht initialisiert ist, wenn der Benutzer nichts eingibt?
Ich will auch mal ein Programm in den Raum werfen: format. Formatiert einen Datenträger. Ist das Programm gefährlich? Nützlich? Das hat mit C++ und allgemein Programmierung überhaupt nichts mehr zu tun.
Manche sagen dass die Entwicklung sicherer System eine Design Frage ist.
-
knivil schrieb:
Nicht alles, was hinkt, ist auch ein Vergleich.
Und mir geht es eher hierdrum:
sry schrieb:
knivil schrieb:
Deswegen gibt es keine C, C++ oder Java spezifischen Fehler.
So ein Quatsch.
Willst du einen Fehler den man nur in C++ machen kann? Falsche Reihenfolge/Abhängigkeit in Header/Initialisierungsliste.
Willst du einen Vergleich der so hinkt wie deiner? Ich kann in C++ auch langsame Programme schreiben, also ist C++ nicht schneller als Java.
-
Nächstes Beispiel:
int main() { char buf[100]; cin.getline(buf, 100); return 0; }Was ist damit?
Was kann passieren?
Wo liegt der Fehler?Die Unschönheit besteht darin, dass evt. nicht alle Zeichen gelesen werden können.
Aber einen direkten Fehler hat das Programm nicht.
-
Bitte ein Bit schrieb:
Nächstes Beispiel:
int main() { char buf[100]; cin.getline(buf, 100); return 0; }Was ist damit?
Was kann passieren?
Wo liegt der Fehler?Keine Ahnung. Kann es sein das buf nicht initialisiert ist, wenn der Benutzer nichts eingibt?
Das kommt drauf an, wie du mit den Daten weiterarbeitest.
Nein, worauf ich hinaus will ist der Buffer-Overflow. Ein Häcker könnte mehr als 100 zeichen eingeben und damit auf dem Stack Speicher weiterschreiben. Und wenn er weiss, was er tut, dann kann er nicht Müll dareinschreiben, sodnern z.B. spezielle Daten, die dann bei entsprechender Größe die Rücksprungadresse einer Funktion überschreiben -> ergo kann er den Programmfluss umlenken udn aht damit die Kontrolle über dein Programm.
Es ist dabei auch egal wie groß der Puffer ist, egal ob 10, 100 oder 1000000430. Der böse Cracker muss halt nur die Größe durch probieren rausfinden und kann dahinter dann seine Daten schreiben.Bitte ein Bit schrieb:
Ich will auch mal ein Programm in den Raum werfen: format. Formatiert einen Datenträger. Ist das Programm gefährlich? Nützlich? Das hat mit C++ und allgemein Programmierung überhaupt nichts mehr zu tun.
Manche sagen dass die Entwicklung sicherer System eine Design Frage ist.
Ja, das stimmt auch zum großen Teil. Aber wenn du einen HDD-Formatierer schreibst, dann willst du ja Schaden anrichten, nur soll dieser gewollt und kontrolliert sein

-
Skym0sh0 schrieb:
Das kommt drauf an, wie du mit den Daten weiterarbeitest.
Nein, worauf ich hinaus will ist der Buffer-Overflow. Ein Häcker könnte mehr als 100 zeichen eingeben und damit auf dem Stack Speicher weiterschreiben.Nein, dazu hast du doch die 100 als Begrenzung beim getline. getline ist kein gets. Deine Beispiele sind allesamt etwas ungünstig, das mit dem system gefiel mir auch nicht, denn da geht es offensichtlich darum, etwas auszuführen.
Viel subtiler sind solche Fehler, bei denen Eingaben nicht geprüft werden, weil dem Programmierer nicht klar ist, dass ein Fehler passieren kann. In C++ ist es schon schwierig dies an einem einfachen Programm zu demonstrieren, aber in C kann ein harmlos aussehender Dreizeiler reichen:
char buf[100]; fgets(buf, 100, stdin); printf("Folgendes wurde eingegeben: "); printf(buf);Sieht alles richtig aus? Ist es aber nicht.
So etwas wäre im Prinzip auch in C++ möglich, wenn man Nutzereingaben ungefiltert an eine entsprechend mächtige Funktion schickt. Das ist auch der Exploit den du mit dem system zeigen wolltest, aber da ist es zu offensichtlich. Dies ist auch der Fehler hinter so Dingen wie SQL-Injections & Co.
-
SeppJ schrieb:
Dies ist auch der Fehler hinter so Dingen wie SQL-Injections & Co.
Mit PreparedStatement geht SQL-Injections auch nicht mehr.
http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html
-
Ist es aber nicht.
Es ist völlig offensichtlich, dass der Nutzer ein '%' mitgeben kann, das sieht doch jeder.
P.S.: Jeder C++-Programmierer weiß, dass man in C für die unformatierte Ausgabe von Strings puts verwendet.