Benutzer-Werkzeuge

Webseiten-Werkzeuge


edv:prg:sichere_programmierung

Sichere Programmierung

FIXME (Entwurf)

Anhaltspunkte:

FIXME

Pufferüberlauf:

Ursache eines Pufferüberlaufs ist das ungeprüfte Kopieren von vom Benutzer gelieferten Daten in Puffer fester Größe. Um einen Pufferüberlauf zu verhindern, müssen also "nur" alle von außen kommenden Daten vor dem Schreiben auf ihre Größe geprüft werden. Und zwar wirklich alle Daten, unabhängig davon, wie sie an das Programm übergeben wurden. Nur die innerhalb des eigenen Programms geprüften Daten sind sicher.

strcpy(), strncpy(), strlcpy()

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
char *strlcpy(char *dest, const char *src, size_t n);

In C sollte man z.B. beim Kopieren eines Strings statt der Funktion strcpy() die Funktion strncpy() verwenden. Während strcpy() alle übergebenen Daten an die Zieladresse kopiert und dabei bei einem zu kleinen Puffer einen Überlauf verursacht, kann bei strncpy() die Größe der zu kopierenden Daten angegeben werden.

:!: Bei Verwendung von strncpy() sollte man unbedingt dafür sorgen, daß der resultierende String explizit mit '\0'-Zeichen terminiert wird!

Weitere Alternative ist die strlcpy(), die garantiert einen NULL-terminierten String als Ergebnis liefert (es werden dabei maximal "size - 1" Zeichen kopiert). Diese Funktion ist jedoch nicht der Bestandteil der GNU C Library. (Sie ist in den FreeBSD, OpenBSD und SUN Solaris Libraries enthalten.)

sprintf(), snprintf()

sprintf(char *dest, const char *fmt, ... );
snprintf(char *dest, size_t n, const char *fmt, ... );

Aus dem selben Grund sollte man an potentiell anfälligen Stellen statt sprintf() die sicherere snprintf() verwenden, die beim Schreiben die maximal erlaubte Größe des Buffers berücksichtigt. Das heißt, es werden in den Buffer dest maximal n Zeichen (samt '\0') geschrieben.

Die snprintf() gibt es aber nicht überall, z.B. Sourcen, die den MS Compilern (z.B. VisualStudio) beiliegen. Dort gibt es _snprintf(), was aber nicht so wie snprintf() funktioniert. Man könnte mit folgenden Zeilen den Code mehr oder weniger übergreifen machen:

#ifdef _WIN32 // Oder eine andere treffende Kennung
#define snprintf _snprintf
#endif

:!: Im Unterschied zu snprintf() gibt _snprintf() -1 zurück (wenn der übergebene Speicher nicht ausreicht), während snprintf() die Länge des Strings (also ohne '\0') zurück gibt, der geschrieben worden wäre, wenn genug Platz vorhanden gewesen wäre.

strcat(), strncat(), strlcat()

strcat(char *dest, const char *src);
strncat(char *dest, const char *src, size_t n);
strlcat(char *dest, const char *src, size_t n);

Eine weitere gefährdete Funktion ist die strcat() - Anhängen eines Strings am Ende eines anderen Strings. Das etwas sicherere Gegenstück dafür heißt strncat(). Die strncat() bekommt im dritten Parameter die Anzahl von Zeichen, die aus dem Quell-String in den Ziel-String kopiert werden dürfen. Dazu (also, zusätzlich zu der o.g. Anzahl!) kommt das terminierende '\0'-Zeichen.

:!: Der dritte Parameter n der strncat() darf also nicht mit der maximal erlaubten Größe des Ziel-Strings (dest) verwechselt werden! Die "n" Zeichen werden zu den sich in "dest" bereits befindenden dazu geschrieben und dann noch das '\0'-Zeichen!

Der sichere Aufruf würde z.B. in etwa wie folgt aussehen:

strncat(dest, src, sizeof(dest) - strlen(dest) - 1);

Weitere Infos zu strncat() sind in Linux Programmer's Manual zu finden.

Funktion, die "wie erwartet" funktioniert, heißt strlcat() - sie bekommt im dritten Parameter die Größe des Ziel-Speichers, damit dieser nicht überschrieben wird und terminiert den Ziel-String selbstständig. Die Funktion ist aber kein Bestandteil der Standard C-Library.

sonst

Für Linux gibt es auch die gcc-Erweiterung StackShield. Dabei wird bei jedem Funktionsaufruf die Rücksprungadresse am Anfang des Datensegments gesichert und vor dem Rücksprung mit der auf dem Stack gespeicherten Version verglichen. Stimmen die Adressen nicht überein, wird das Programm beendet oder die ursprüngliche Adresse restauriert. Der dazu notwendige Code wird am Anfang und Ende jedes Funktionsaufrufs eingefügt.

Siehe auch: Restricted Shell


Stand: 15.11.2012 - in Arbeit
: Jürgen Kreick

EOF

edv/prg/sichere_programmierung.txt · Zuletzt geändert: 2020/01/11 01:23 von 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki