Verwendung derselben Variable für mehrere Zwecke
Beschreibung
Die Verwendung derselben Variable für mehrere Zwecke tritt auf, wenn Code ein aufrufbares Element, einen Block oder ein anderes Code-Element enthält, in dem dieselbe Variable verwendet wird, um mehr als eine eindeutige Aufgabe zu steuern oder mehr als einen Datentyp zu speichern. Diese Praxis verletzt das Single-Responsibility-Prinzip auf Variablenebene und macht Code schwieriger zu verstehen, zu debuggen und zu warten. Wenn sich die Bedeutung einer Variable im Verlauf einer Funktion ändert, wird es schwierig, den aktuellen Zustand und die Absicht des Codes zu verfolgen.
Risiko
Die Wiederverwendung von Variablen für mehrere Zwecke hat Sicherheitsimplikationen. Die sich ändernde Bedeutung von Variablen macht Code-Reviews für Sicherheitsprobleme schwieriger. Logikfehler sind wahrscheinlicher, wenn sich die Semantik einer Variable mitten in der Funktion ändert. Sicherheitssensible Operationen können veraltete oder falsche Werte verwenden. Typverwirrung kann auftreten, wenn eine Variable verschiedene Datentypen speichert. Pufferbehandlungsfehler werden wahrscheinlicher bei wiederverwendeten Puffervariablen. Das Debugging von Sicherheitsvorfällen wird durch unklare Variablensemantik erschwert. Statische Analyse kann Schwachstellen aufgrund komplexen Datenflusses übersehen.
Lösung
Verwenden Sie separate Variablen für jeden unterschiedlichen Zweck. Wählen Sie beschreibende Variablennamen, die ihren Zweck klar angeben. Begrenzen Sie den Variablenbereich auf das notwendige Minimum. Initialisieren Sie Variablen zum Zeitpunkt der Deklaration, wenn möglich. Verwenden Sie const/final für Werte, die sich nicht ändern sollten. Refaktorieren Sie lange Funktionen, die zur Variablenwiederverwendung verleiten, in kleinere Funktionen. Wenden Sie statische Analysetools an, die Variablenwiederverwendungsmuster erkennen. Verwenden Sie Code-Review-Richtlinien, die Mehrzweckvariablen kennzeichnen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Sonstiges | Bereich: Sonstiges Reduzierte Wartbarkeit - Code ist schwieriger zu verstehen, wenn sich Variablenbedeutungen ändern. |
| Sonstiges | Bereich: Sonstiges Erhöhte Analysekomplexität - Sicherheitsanalyse wird durch Mehrzweckvariablen erschwert. |
| Integrität | Bereich: Integrität Logikfehler - Falsche Werte können verwendet werden, wenn sich der Variablenzweck ändert. |
Beispielcode und Lösung
Verwundbarer Code
// Verwundbar: Dieselbe Variable für mehrere Zwecke verwendet
void verwundbare_daten_verarbeiten(char* eingabe) {
int i; // Für mehrere Zwecke verwendet!
// Erster Zweck: Schleifenzähler für Eingabevalidierung
for (i = 0; i < strlen(eingabe); i++) {
if (!isalnum(eingabe[i])) {
return; // Ungültige Eingabe
}
}
// Zweiter Zweck: Fehlercode
i = validate_format(eingabe);
if (i != 0) {
log_error(i); // Verwendet i als Fehlercode
return;
}
// Dritter Zweck: Byte-Anzahl
i = process_input(eingabe);
printf("Verarbeitete %d Bytes\n", i); // Verwendet i als Zähler
// Vierter Zweck: Dateideskriptor
i = open("ausgabe.txt", O_WRONLY); // Verwendet i als fd!
if (i < 0) {
return;
}
write(i, eingabe, strlen(eingabe));
close(i);
}
// Verwundbar: Puffer für verschiedene Zwecke wiederverwendet
void verwundbarer_wiederverwendeter_puffer(const char* dateiname) {
char buffer[1024]; // Für alles wiederverwendet
// Erste Verwendung: Konfigurationsdatei lesen
FILE* f = fopen("config.txt", "r");
fgets(buffer, sizeof(buffer), f);
fclose(f);
process_config(buffer);
// Zweite Verwendung: Benutzereingabe lesen (kann noch Config-Daten enthalten!)
// Bug: Puffer nicht gelöscht, könnte Config-Daten leaken
fgets(buffer, sizeof(buffer), stdin);
// Dritte Verwendung: Ausgabenachricht formatieren
snprintf(buffer, sizeof(buffer), "Benutzer sagte: %s", buffer); // BUG!
// Verwendet buffer sowohl als Quelle als auch als Ziel!
// Vierte Verwendung: Passwort-Hash speichern
compute_hash(buffer, buffer); // Passwort-Hash im selben Puffer!
// Puffer enthält jetzt sensible Daten
}
// Verwundbar: Java mit Mehrzweckvariablen
public class VerwundbareVerarbeitung {
public void benutzerVerarbeiten(String eingabe) {
Object ergebnis; // Für verschiedene Typen wiederverwendet!
// Erste Verwendung: als User-Objekt
ergebnis = userRepository.findByName(eingabe);
if (ergebnis == null) {
return;
}
User user = (User) ergebnis; // Typ-Casting
// Zweite Verwendung: als Permission-Liste
ergebnis = permissionService.getPermissions(user.getId());
List<Permission> perms = (List<Permission>) ergebnis; // Anderer Typ!
// Dritte Verwendung: als Validierungsergebnis
ergebnis = validator.validate(user, perms);
Boolean istGültig = (Boolean) ergebnis; // Noch ein anderer Typ!
// Vierte Verwendung: als String-Nachricht
ergebnis = "Verarbeitung abgeschlossen für " + user.getName();
log((String) ergebnis);
// Problem: Typverwirrung, schwer zu verfolgen was 'ergebnis' enthält
}
}
Sichere Lösung
// Sicher: Separate Variablen für jeden Zweck
void sichere_daten_verarbeiten(const char* eingabe) {
// Jede Variable hat einen klaren Zweck
size_t eingabe_länge = strlen(eingabe);
// Dedizierter Schleifenzähler für Validierung
for (size_t zeichen_index = 0; zeichen_index < eingabe_länge; zeichen_index++) {
if (!isalnum(eingabe[zeichen_index])) {
return;
}
}
// Dedizierte Variable für Fehlercode
int validierungsfehler = validate_format(eingabe);
if (validierungsfehler != 0) {
log_error(validierungsfehler);
return;
}
// Dedizierte Variable für Byte-Anzahl
size_t verarbeitete_bytes = process_input(eingabe);
printf("Verarbeitete %zu Bytes\n", verarbeitete_bytes);
// Dedizierte Variable für Dateideskriptor
int ausgabe_fd = open("ausgabe.txt", O_WRONLY);
if (ausgabe_fd < 0) {
return;
}
write(ausgabe_fd, eingabe, eingabe_länge);
close(ausgabe_fd);
}
// Sicher: Separate Puffer für verschiedene Zwecke
void sichere_separate_puffer(const char* dateiname) {
char config_buffer[1024];
char benutzer_eingabe[1024];
char ausgabe_nachricht[2048];
char passwort_hash[65]; // SHA-256 hex
// Config lesen - dedizierter Puffer
FILE* f = fopen("config.txt", "r");
if (f) {
fgets(config_buffer, sizeof(config_buffer), f);
fclose(f);
process_config(config_buffer);
}
// Benutzereingabe lesen - separater Puffer
if (fgets(benutzer_eingabe, sizeof(benutzer_eingabe), stdin)) {
// Ausgabe formatieren - dedizierter Ausgabepuffer
snprintf(ausgabe_nachricht, sizeof(ausgabe_nachricht),
"Benutzer sagte: %s", benutzer_eingabe);
}
// Hash berechnen - dedizierter Hash-Puffer
compute_hash(benutzer_eingabe, passwort_hash);
// Sensible Daten löschen
memset(passwort_hash, 0, sizeof(passwort_hash));
memset(benutzer_eingabe, 0, sizeof(benutzer_eingabe));
}
// Sicher: Java mit Einzelzweck-Variablen
public class SichereVerarbeitung {
public void benutzerVerarbeiten(String eingabe) {
// Jede Variable hat einen klaren Zweck
User user = userRepository.findByName(eingabe);
if (user == null) {
return;
}
List<Permission> berechtigungen = permissionService.getPermissions(user.getId());
boolean istGültig = validator.validate(user, berechtigungen);
if (!istGültig) {
return;
}
String logNachricht = "Verarbeitung abgeschlossen für " + user.getName();
log(logNachricht);
}
}
CVE-Beispiele
- CVE-2023-26463: Ein IPSec-VPN-Produkt verwendete Variablen innerhalb einer Funktion wieder, was zu Zugriffskontrollfehlern und Pointer-Dereferenzierungs-Schwachstellen beitrug.
Verwandte CWEs
- CWE-1078: Unangemessener Quellcode-Stil oder Formatierung (Eltern)
- CWE-1006: Schlechte Programmierpraktiken (Kategoriemitglied)
- CWE-704: Falsche Typkonvertierung oder Cast (verwandt)
Referenzen
-
MITRE Corporation. "CWE-1109: Use of Same Variable for Multiple Purposes." https://cwe.mitre.org/data/definitions/1109.html
-
Martin, Robert C. "Clean Code" - Aussagekräftige Namen.