Wie kann man in C sicher mit Zeichenketten umgehen, um Pufferüberläufe zu vermeiden?
- Einführung
- Größe des Buffers kennen und Grenzen beachten
- Sichere Funktionen verwenden
- Manuelle Kontrolle und Null-Terminierung sicherstellen
- Alternativen zur Standard-String-Verarbeitung
- Beispiel für sicheres Kopieren mit strlcpy (Plattformabhängig)
- Prüfung der Eingabelängen
- Zusammenfassung
Einführung
In der Programmiersprache C sind Zeichenketten (Strings) eine Sequenz von Zeichen, die typischerweise als Array von `char` gespeichert und mit einem abschließenden Null-Byte (`\0`) terminiert werden. Da C keine eingebaute Schutzmechanismen gegen Pufferüberläufe beim Umgang mit Zeichenketten bietet, besteht die Gefahr, dass beim Kopieren oder Verarbeiten von Strings mehr Zeichen als der reservierte Speicherbereich verwendet werden. Solche Pufferüberläufe führen zu undefiniertem Verhalten, Sicherheitslücken und können Programme zum Absturz bringen. Daher ist es essenziell, bei der Arbeit mit Zeichenketten stets sicherheitsbewusst zu programmieren.
Größe des Buffers kennen und Grenzen beachten
Der wichtigste Grundsatz für den sicheren Umgang mit Strings in C ist, immer die Größe des Zielpuffers zu kennen und sicherzustellen, dass niemals mehr Daten hineingeschrieben werden, als darin Platz finden. Dies schließt auch das abschließende Null-Byte ein. Beispielsweise sollte bei einem Array der Größe 20 niemals versucht werden, mehr als 19 Zeichen zu kopieren oder zu speichern.
Sichere Funktionen verwenden
Die Standardbibliothek enthält viele String-Funktionen wie `strcpy` oder `strcat`, die keine Größentests durchführen und leicht zu Pufferüberläufen führen können. Stattdessen sollte man stets Varianten verwenden, die eine maximale Anzahl von Zeichen akzeptieren und diese berücksichtigen. So wurden mit C11 unter anderem Funktionen wie `strncpy_s` und `strcat_s` eingeführt, allerdings sind diese nicht in allen Umgebungen verbreitet. Häufigere und portablere Alternativen sind `strncpy`, die jedoch Vorsicht erfordern, da sie nicht immer Null-terminieren. Eine sicherere Alternative ist die Nutzung von ` `-Funktionen in Kombination mit kontrollierter Puffergröße.
Außerdem gibt es plattformabhängige Funktionen wie `strlcpy` und `strlcat`, die auf vielen Systemen verfügbar sind und besonders benutzerfreundlich für sichere String-Kopien und -Konkatenationen sind, da sie die Größe des Puffers berücksichtigen und stets für Null-Terminierung sorgen.
Manuelle Kontrolle und Null-Terminierung sicherstellen
Beim Arbeiten mit Funktionen wie `strncpy`, die bei zu langen Quellstrings nicht automatisch nullterminieren, muss man selbst darauf achten, das Zielarray am Ende manuell mit `\0` zu terminieren, um undefiniertes Verhalten zu vermeiden. Dies ist entscheidend, damit Funktionen, die sich auf die Nullterminierung verlassen (z.B. `printf("%s")`), korrekt arbeiten.
Alternativen zur Standard-String-Verarbeitung
Eine weitere Möglichkeit ist die Verwendung von dynamischen Speicherstrukturen mit `malloc` und `realloc`, um die Puffergröße flexibel an die Größe der Zeichenkette anzupassen. Auch das Arbeiten mit `snprintf` anstelle von `sprintf` ist eine gängige Methode, da `snprintf` die maximale Größe des Puffers als Argument bekommt und somit Pufferüberläufe verhindert. Diese Funktion formt Strings sicher in den Zielpuffer um.
Beispiel für sicheres Kopieren mit strlcpy (Plattformabhängig)
char dest ;const char *src = "Das ist ein sicherer String";strlcpy(dest, src, sizeof(dest)); // dest wird korrekt kopiert und nullterminiert
Falls `strlcpy` nicht verfügbar ist, kann `snprintf` benutzt werden:
char dest ;const char *src = "Das ist ein sicherer String";snprintf(dest, sizeof(dest), "%s", src);Prüfung der Eingabelängen
Bei Benutzereingaben oder Daten aus unsicheren Quellen ist es besonders wichtig, die Länge der Eingabe mittels `strlen` oder anderen Mitteln zu prüfen, bevor sie in einen Puffer kopiert wird. So kann man etwa Eingaben ablehnen oder abschneiden, bevor sie im Programm weiterverarbeitet werden.
Zusammenfassung
Zusammenfassend ist für die sichere Behandlung von Zeichenketten in C entscheidend, stets die Puffergrößen zu kennen, Funktionen zu benutzen, die Begrenzungen respektieren und die Nullterminierung sicherzustellen. Dabei helfen Funktionen wie `strlcpy`, `snprintf` oder die neuen `*_s`-Familien, sowie eine bewusste Programmierweise mit kontrollierter Längenprüfung und Pufferverwaltung. Nur so lassen sich Pufferüberläufe verhindern und die Sicherheit sowie Stabilität des Programms gewährleisten.
