Unsachgemäße Initialisierung
Beschreibung
Unsachgemäße Initialisierung tritt auf, wenn eine Anwendung kritische Variablen, Datenstrukturen oder Ressourcen vor der Verwendung nicht ordnungsgemäß initialisiert. Dies umfasst das Versäumnis, Speicherallokationen zu initialisieren, keine Standardwerte für sicherheitskritische Variablen zu setzen, Datenstrukturen nur teilweise zu initialisieren oder sich auf undefinierte Anfangswerte zu verlassen. Die resultierenden undefinierten oder angreiferkontrollierten Werte können zu Sicherheitslücken führen.
Risiko
Sicherheitskritische Flags können standardmäßig auf "erlaubt" stehen. Nicht initialisierte Pointer verursachen Abstürze oder beliebigen Speicherzugriff. Sensible Daten aus vorherigen Operationen werden im Speicher exponiert. Authentifizierungsvariablen können Prüfungen umgehen, wenn sie nicht ordnungsgemäß initialisiert werden. Kryptographische Schlüssel können schwach oder vorhersehbar sein. Pufferinhalte können Informationen an Angreifer preisgeben.
Lösung
Initialisieren Sie alle Variablen immer explizit. Verwenden Sie Sprachfunktionen, die Initialisierung erzwingen. Initialisieren Sie sicherheitskritische Variablen auf sichere Standardwerte (standardmäßig verweigern). Verwenden Sie Konstruktoren und Initialisierungslisten. Leeren Sie Speicherallokationen vor der Verwendung. Implementieren Sie statische Analyse zur Erkennung nicht initialisierter Variablen.
Häufige Konsequenzen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Informationsoffenlegung Nicht initialisierter Speicher kann sensible Daten enthalten. |
| Autorisierung | Bereich: Zugriffskontrollumgehung Nicht initialisierte Flags können standardmäßig "erlauben" sein. |
| Verfügbarkeit | Bereich: Abstürze Nicht initialisierte Pointer verursachen Abstürze. |
Beispielcode + Lösungscode
Verwundbarer Code
// VERWUNDBAR: Nicht initialisierte Variablen in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// VERWUNDBAR: Nicht initialisiertes Sicherheits-Flag
int check_access_vulnerable(int user_id) {
int is_admin; // VERWUNDBAR: Nicht initialisiert
if (user_id == ADMIN_USER_ID) {
is_admin = 1;
}
// VERWUNDBAR: is_admin nicht initialisiert wenn nicht Admin
// Stack-Müll könnte ungleich Null sein!
return is_admin; // Könnte Müllwert zurückgeben und Zugriff erlauben
}
// VERWUNDBAR: Nicht initialisierter Puffer
void send_response_vulnerable(int socket) {
char buffer[1024]; // VERWUNDBAR: Enthält Stack-Müll
// Nur teilweise gefüllt
strcpy(buffer, "Response: OK");
// VERWUNDBAR: Sendet alle 1024 Bytes inklusive nicht initialisierter Daten
send(socket, buffer, sizeof(buffer), 0);
}
// VERWUNDBAR: Nicht initialisierte Struktur
typedef struct {
char* username;
char* password;
int permissions;
int is_authenticated;
} UserSession;
UserSession* create_session_vulnerable() {
// VERWUNDBAR: malloc initialisiert Speicher nicht
UserSession* session = malloc(sizeof(UserSession));
// Vergessen alle Felder zu initialisieren
session->username = "guest";
// VERWUNDBAR: password, permissions, is_authenticated nicht initialisiert!
return session;
}
// VERWUNDBAR: Teilweise initialisiertes Array
void process_data_vulnerable() {
int data[100]; // VERWUNDBAR: Nicht initialisiert
// Nur einige Elemente gesetzt
for (int i = 0; i < 50; i++) {
data[i] = i;
}
// VERWUNDBAR: Verwendung nicht initialisierter Elemente
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += data[i]; // data[50-99] sind Müll
}
}
// VERWUNDBAR: Nicht initialisierter Pointer
void use_pointer_vulnerable() {
char* ptr; // VERWUNDBAR: Nicht initialisiert
if (some_condition) {
ptr = get_data();
}
// VERWUNDBAR: ptr könnte nicht initialisiert sein
printf("%s\n", ptr); // Absturz oder beliebiges Lesen
}
# VERWUNDBAR: Python-Initialisierungsprobleme
class VulnerableUser:
# VERWUNDBAR: Instanzvariablen nicht in __init__ initialisiert
def authenticate(self, username, password):
if check_credentials(username, password):
self.is_authenticated = True
self.username = username
def check_permission(self, resource):
# VERWUNDBAR: is_authenticated existiert möglicherweise nicht
if self.is_authenticated: # AttributeError wenn authenticate nicht aufgerufen
return True
return False
# VERWUNDBAR: Bedingte Initialisierung
def process_request_vulnerable(request):
result = None # Teilweise Initialisierung
if request.type == 'A':
result = handle_type_a(request)
elif request.type == 'B':
result = handle_type_b(request)
# VERWUNDBAR: Wenn Typ 'C' ist, ist result None
# VERWUNDBAR: Nimmt an, dass result immer gültig ist
return result.data # AttributeError wenn result None ist
# VERWUNDBAR: Dictionary ohne Standardwerte
def get_config_vulnerable():
config = {}
if os.path.exists('config.json'):
config = json.load(open('config.json'))
# VERWUNDBAR: Nimmt an, dass Schlüssel existieren
db_host = config['database']['host'] # KeyError wenn nicht in Datei
return db_host
# VERWUNDBAR: Klasse ohne ordnungsgemäße Standardwerte
class VulnerableSession:
def __init__(self):
# VERWUNDBAR: Sicherheitskritische Felder nicht initialisiert
pass
def set_user(self, user):
self.user = user
self.permissions = user.permissions
def can_access(self, resource):
# VERWUNDBAR: permissions existiert möglicherweise nicht
return resource in self.permissions
// VERWUNDBAR: Java-Initialisierungsprobleme
public class VulnerableInitialization {
// VERWUNDBAR: Instanzfeld nicht initialisiert
private Boolean isAdmin; // null standardmäßig
public boolean checkAccess() {
// VERWUNDBAR: NPE wenn isAdmin nie gesetzt
return isAdmin; // Auto-Unboxing von null wirft NPE
}
// VERWUNDBAR: Array nicht ordnungsgemäß initialisiert
private int[] permissions;
public void setPermission(int index, int value) {
// VERWUNDBAR: permissions-Array könnte null sein
permissions[index] = value; // NPE
}
// VERWUNDBAR: Teilweise Initialisierung im Konstruktor
private String username;
private String password;
private int accessLevel;
public VulnerableInitialization(String user) {
this.username = user;
// VERWUNDBAR: password und accessLevel nicht initialisiert
// accessLevel ist standardmäßig 0, was Zugriff gewähren könnte!
}
// VERWUNDBAR: Bedingte Initialisierung
private Connection dbConnection;
public void connect(boolean useSSL) {
if (useSSL) {
dbConnection = createSSLConnection();
}
// VERWUNDBAR: dbConnection null wenn useSSL false
}
public void query(String sql) {
// VERWUNDBAR: NPE wenn connect mit false aufgerufen wurde
dbConnection.execute(sql);
}
}
// VERWUNDBAR: Builder ohne Prüfung erforderlicher Felder
public class VulnerableBuilder {
private String apiKey;
private String endpoint;
private Integer timeout;
public VulnerableBuilder apiKey(String key) {
this.apiKey = key;
return this;
}
public APIClient build() {
// VERWUNDBAR: Prüft nicht, ob erforderliche Felder gesetzt sind
return new APIClient(apiKey, endpoint, timeout);
}
}
// VERWUNDBAR: JavaScript-Initialisierungsprobleme
class VulnerableService {
constructor() {
// VERWUNDBAR: Keine Initialisierung kritischer Felder
}
// VERWUNDBAR: Feld möglicherweise nicht initialisiert
async processRequest(req) {
// VERWUNDBAR: this.config könnte undefined sein
const endpoint = this.config.apiEndpoint;
return fetch(endpoint);
}
// VERWUNDBAR: Bedingte Initialisierung
initialize(options) {
if (options.debug) {
this.logger = new Logger();
}
// VERWUNDBAR: logger undefined wenn nicht Debug-Modus
}
log(message) {
// VERWUNDBAR: TypeError wenn logger nicht initialisiert
this.logger.write(message);
}
}
// VERWUNDBAR: Objekt ohne Standardwerte
function createUser(data) {
const user = {
name: data.name
// VERWUNDBAR: Fehlende role, permissions, etc.
};
// VERWUNDBAR: Nimmt an, alle Eigenschaften existieren
if (user.role === 'admin') { // undefined, nie wahr
// Aber auch nie ordnungsgemäß verweigert
}
return user;
}
// VERWUNDBAR: Array-Element-Zugriff ohne Initialisierung
function processItems(count) {
const items = new Array(count); // Erstellt sparse Array
// VERWUNDBAR: Elemente sind undefined
for (let i = 0; i < count; i++) {
// items[i] ist undefined!
console.log(items[i].value); // TypeError
}
}
Lösungscode
// SICHER: Ordnungsgemäße Initialisierung in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// SICHER: Auf sicheren Standardwert initialisieren
int check_access_safe(int user_id) {
int is_admin = 0; // SICHER: Standard auf Verweigern
if (user_id == ADMIN_USER_ID) {
is_admin = 1;
}
return is_admin;
}
// SICHER: Puffer mit Null initialisieren
void send_response_safe(int socket) {
char buffer[1024] = {0}; // SICHER: Null-initialisiert
// Oder memset verwenden
// char buffer[1024];
// memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "Response: OK");
// SICHER: Nur tatsächliche Datenlänge senden
send(socket, buffer, strlen(buffer), 0);
}
// SICHER: Vollständig initialisierte Struktur
UserSession* create_session_safe() {
// SICHER: calloc initialisiert Speicher mit Null
UserSession* session = calloc(1, sizeof(UserSession));
if (!session) return NULL;
// SICHER: Explizite Initialisierung aller Felder
session->username = NULL;
session->password = NULL;
session->permissions = 0;
session->is_authenticated = 0; // Standard auf nicht authentifiziert
return session;
}
// SICHER: Initialisierungsfunktion verwenden
void init_session(UserSession* session) {
memset(session, 0, sizeof(UserSession));
session->permissions = DEFAULT_PERMISSIONS;
}
// SICHER: Vollständig initialisiertes Array
void process_data_safe() {
int data[100] = {0}; // SICHER: Alle Elemente Null
for (int i = 0; i < 50; i++) {
data[i] = i;
}
// SICHER: Alle Elemente haben bekannte Werte
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += data[i];
}
}
// SICHER: Pointer auf NULL initialisieren
void use_pointer_safe() {
char* ptr = NULL; // SICHER: Auf NULL initialisiert
if (some_condition) {
ptr = get_data();
}
// SICHER: NULL-Prüfung vor Verwendung
if (ptr != NULL) {
printf("%s\n", ptr);
}
}
# SICHER: Python mit ordnungsgemäßer Initialisierung
class SafeUser:
def __init__(self):
# SICHER: Alle Attribute mit sicheren Standardwerten initialisieren
self.is_authenticated = False
self.username = None
self.permissions = []
def authenticate(self, username, password):
if check_credentials(username, password):
self.is_authenticated = True
self.username = username
self.permissions = get_user_permissions(username)
def check_permission(self, resource):
# SICHER: is_authenticated existiert immer
if self.is_authenticated:
return resource in self.permissions
return False
# SICHER: Dataclasses für garantierte Initialisierung verwenden
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class SafeSession:
username: str
is_authenticated: bool = False
permissions: List[str] = field(default_factory=list)
access_level: int = 0
# SICHER: Dictionary mit Standardwerten
def get_config_safe():
default_config = {
'database': {
'host': 'localhost',
'port': 5432
},
'debug': False
}
config = default_config.copy()
if os.path.exists('config.json'):
with open('config.json') as f:
loaded = json.load(f)
# SICHER: Mit Standardwerten zusammenführen
deep_merge(config, loaded)
return config
# SICHER: get() mit Standardwerten verwenden
def process_request_safe(request):
handlers = {
'A': handle_type_a,
'B': handle_type_b,
}
# SICHER: Standard-Handler wenn Typ nicht gefunden
handler = handlers.get(request.type, handle_unknown)
result = handler(request)
# SICHER: Ergebnis vor Verwendung prüfen
if result and hasattr(result, 'data'):
return result.data
return None
// SICHER: Java mit ordnungsgemäßer Initialisierung
public class SafeInitialization {
// SICHER: Mit sicherem Standardwert initialisieren
private boolean isAdmin = false;
public boolean checkAccess() {
return isAdmin; // Keine NPE, standardmäßig immer false
}
// SICHER: Array initialisieren
private int[] permissions = new int[10]; // Mit Nullen initialisiert
public void setPermission(int index, int value) {
if (index >= 0 && index < permissions.length) {
permissions[index] = value;
}
}
// SICHER: Vollständige Initialisierung im Konstruktor
private final String username;
private final String password;
private final int accessLevel;
public SafeInitialization(String user, String pass, int level) {
this.username = Objects.requireNonNull(user, "Username erforderlich");
this.password = pass != null ? pass : "";
this.accessLevel = level;
}
// SICHER: Optional für nullable Felder verwenden
private Optional<Connection> dbConnection = Optional.empty();
public void connect(boolean useSSL) {
if (useSSL) {
dbConnection = Optional.of(createSSLConnection());
} else {
dbConnection = Optional.of(createConnection());
}
}
public void query(String sql) {
// SICHER: Explizite Behandlung des nicht initialisierten Zustands
dbConnection.orElseThrow(() ->
new IllegalStateException("Nicht verbunden")
).execute(sql);
}
}
// SICHER: Builder mit Validierung
public class SafeBuilder {
private String apiKey;
private String endpoint;
private Integer timeout = 30000; // Standardwert
public SafeBuilder apiKey(String key) {
this.apiKey = key;
return this;
}
public SafeBuilder endpoint(String url) {
this.endpoint = url;
return this;
}
public APIClient build() {
// SICHER: Erforderliche Felder validieren
Objects.requireNonNull(apiKey, "API-Schlüssel erforderlich");
Objects.requireNonNull(endpoint, "Endpoint erforderlich");
return new APIClient(apiKey, endpoint, timeout);
}
}
// SICHER: JavaScript mit ordnungsgemäßer Initialisierung
class SafeService {
constructor(config = {}) {
// SICHER: Mit Standardwerten initialisieren
this.config = {
apiEndpoint: 'https://api.default.com',
timeout: 5000,
retries: 3,
...config // Mit bereitgestellter Konfiguration überschreiben
};
this.logger = config.debug ? new Logger() : new NullLogger();
this.initialized = true;
}
async processRequest(req) {
// SICHER: config ist immer initialisiert
const endpoint = this.config.apiEndpoint;
return fetch(endpoint);
}
log(message) {
// SICHER: logger ist immer initialisiert (möglicherweise NullLogger)
this.logger.write(message);
}
}
// SICHER: Objekt mit allen erforderlichen Standardwerten
function createUser(data) {
const user = {
name: data.name || 'Unbekannt',
email: data.email || null,
role: data.role || 'guest',
permissions: data.permissions || [],
isActive: data.isActive ?? true,
createdAt: new Date()
};
// SICHER: role ist immer definiert
if (user.role === 'admin') {
user.permissions.push('admin:*');
}
return user;
}
// SICHER: Array ordnungsgemäß initialisiert
function processItems(count) {
// SICHER: Array.from erstellt ordnungsgemäß initialisiertes Array
const items = Array.from({ length: count }, (_, i) => ({
id: i,
value: 0,
processed: false
}));
for (const item of items) {
console.log(item.value); // Sicherer Zugriff
}
return items;
}
// SICHER: Nullish Coalescing und Optional Chaining verwenden
function getConfig(options) {
return {
host: options?.database?.host ?? 'localhost',
port: options?.database?.port ?? 5432,
ssl: options?.database?.ssl ?? false
};
}
Ausgenutzt in der Praxis
Privilegieneskalation
Nicht initialisierte isAdmin-Flags, die standardmäßig auf true stehen.
Informationsoffenlegung
Nicht initialisierte Puffer, die Speicherinhalte preisgeben.
Denial of Service
Null Pointer-Dereferenzierungen durch nicht initialisierte Pointer.
Werkzeuge zum Testen/Ausnutzen
-
Speicher-Sanitizer (MSan für nicht initialisierte Lesevorgänge).
-
Statische Analysatoren (Coverity, PVS-Studio).
-
Compiler-Warnungen (-Wuninitialized).
CVE-Beispiele
-
CVE-2019-14899: Nicht initialisierte Speicheroffenlegung im Linux-Kernel.
-
CVE-2020-14386: Ausnutzung nicht initialisierter Stack-Variable.
Referenzen
-
MITRE. "CWE-665: Improper Initialization." https://cwe.mitre.org/data/definitions/665.html
-
CERT C: Variablen vor Verwendung initialisieren.