Unzureichende Präzision oder Genauigkeit einer reellen Zahl
Beschreibung
Unzureichende Präzision oder Genauigkeit einer reellen Zahl tritt auf, wenn ein Produkt reelle Zahlen mit einer Implementierung verarbeitet, bei der die Darstellung die erforderliche Genauigkeit und Präzision im Nachkommateil nicht bewahrt, was zu fehlerhaften Ergebnissen führt. Wenn Sicherheitsentscheidungen oder Berechnungen von hochpräzisen Zahlen abhängen -- wie bei Finanztransaktionen oder Preisberechnungen -- können kleine Abweichungen ausgenutzt werden. Es existieren mehrere Speichermethoden einschließlich Festkomma-, Gleitkomma- und verhältnisbasierter Darstellungen, jeweils mit Genauigkeitsbeschränkungen. Probleme entstehen, wenn Brüche nicht in festen Ziffern dargestellt werden können, periodische Dezimalzahlen auftreten oder transzendente Zahlen erscheinen. Rundungsfehler führen dazu, dass Computerergebnisse von mathematisch korrekten Resultaten abweichen.
Risiko
Unzureichende Präzision hat schwerwiegende Auswirkungen. Fehler bei Finanzberechnungen, die zu monetären Verlusten führen. Sicherheitsumgehung durch Berechnungsmanipulation. Buffer Overflows durch fehlberechnete Grenzen. Anwendungsabstürze durch undefinierte Ergebnisse. Endlosschleifen durch Präzisionsfehler. Ausfälle sicherheitskritischer Systeme. Ausnutzbare Rundungsfehler. Hohe Wahrscheinlichkeit, wenn präzise Berechnungen Sicherheitsentscheidungen bestimmen.
Lösung
Genauere Darstellungen reeller Zahlen während der Architektur- und Designphase übernehmen. Verhältnisse von BigInts für extrem feine Präzision verwenden. Unum-Reals für verbesserte Genauigkeit implementieren. Speicher- und CPU-Kompromisse bewerten, da Alternativen zur Hardware-Gleitkommaberechnung Berechnungen typischerweise auf langsamere Software-Implementierungen verlagern. Festkomma-Arithmetik verwenden, wenn Präzisionsanforderungen klar definiert sind, während der Implementierungsphase.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit Undefinierte Ergebnisse verursachen oft Abstürze, Stillstände oder Endlosschleifen bei Überlaufbedingungen. |
| Integrität | Bereich: Integrität Fehlberechnete Werte erzeugen falsche Antworten mit Sicherheitsauswirkungen. |
| Vertraulichkeit | Bereich: Vertraulichkeit, Integrität, Zugangskontrolle Kann Buffer Overflows auslösen, die beliebige Codeausführung durch Grenzwert-Fehlberechnung ermöglichen. |
Beispielcode
Verwundbarer Code
// VERWUNDBAR: Gleitkomma-Präzisionsprobleme
// VERWUNDBAR: Mullers Rekurrenz mit Standard-Floats
fn vulnerable_recurrence(y: f64, z: f64) -> f64 {
// Diese Formel sollte gegen 5.0 konvergieren
// Aber Gleitkommafehler führen zur Divergenz
108.0 - ((815.0 - 1500.0 / z) / y)
}
fn vulnerable_muller_sequence() {
let mut y = 4.0_f64;
let mut z = 4.25_f64;
// VERWUNDBAR: Präzisionsverlust verursacht falsche Konvergenz
for i in 0..30 {
let next = vulnerable_recurrence(y, z);
println!("Iteration {}: {}", i, next);
z = y;
y = next;
// Erwartet: konvergiert gegen 5.0
// Tatsächlich: divergiert gegen 100.0 durch Präzisionsfehler
}
}
# VERWUNDBAR: Python Gleitkomma-Probleme
# VERWUNDBAR: Finanzberechnung mit float
def vulnerable_calculate_total(prices):
# VERWUNDBAR: Gleitkomma-Akkumulationsfehler
total = 0.0
for price in prices:
total += price
return total
# Beispiel: 0.1 + 0.2 != 0.3 bei Gleitkomma
# >>> 0.1 + 0.2
# 0.30000000000000004
# VERWUNDBAR: Währungsumrechnung
def vulnerable_convert_currency(amount, rate):
# VERWUNDBAR: Präzisionsverlust bei Umrechnung
return amount * rate
# Kleine Fehler summieren sich über viele Transaktionen
# VERWUNDBAR: Zinsberechnung
def vulnerable_compound_interest(principal, rate, years, compounds_per_year):
# VERWUNDBAR: Exponentielle Berechnung verstärkt Präzisionsfehler
return principal * (1 + rate / compounds_per_year) ** (compounds_per_year * years)
# VERWUNDBAR: Division, die exakt sein sollte
def vulnerable_split_bill(total, num_people):
# VERWUNDBAR: Teilt möglicherweise nicht gleichmäßig
per_person = total / num_people
calculated_total = per_person * num_people
# calculated_total stimmt möglicherweise wegen Präzision nicht mit total überein
return per_person
# VERWUNDBAR: Vergleich mit Gleitkomma
def vulnerable_balance_check(balance, withdrawal):
# VERWUNDBAR: Direkter Gleitkomma-Vergleich
remaining = balance - withdrawal
if remaining == 0.0: # Wird möglicherweise nie exakt Null
return "Konto leer"
elif remaining < 0:
return "Unzureichendes Guthaben"
else:
return "OK"
// VERWUNDBAR: C Gleitkomma-Probleme
#include <stdio.h>
#include <math.h>
// VERWUNDBAR: Puffergrößenberechnung mit float
void vulnerable_buffer_allocation(float data_size, float factor) {
// VERWUNDBAR: Präzisionsverlust bei Größenberechnung
int buffer_size = (int)(data_size * factor);
// Wenn factor = 1.1 und data_size = 100
// Erwartet: 110, könnte aber 109 sein wegen Abschneidung
char* buffer = malloc(buffer_size);
// Puffer möglicherweise zu klein für tatsächliche Daten
}
// VERWUNDBAR: Schleife mit Gleitkomma-Zähler
void vulnerable_float_loop() {
// VERWUNDBAR: Terminiert möglicherweise nicht wie erwartet
for (float f = 0.0f; f != 1.0f; f += 0.1f) {
printf("%f\n", f);
// 0.1 kann in Binär nicht exakt dargestellt werden
// Schleife könnte 1.0 überschreiten und nie terminieren
}
}
// VERWUNDBAR: Sicherheitsprüfung mit Float-Vergleich
int vulnerable_access_check(float user_level, float required_level) {
// VERWUNDBAR: Direkter Gleichheitsvergleich
if (user_level == required_level) {
return 1; // Zugang gewähren
}
// Kann fehlschlagen, auch wenn Werte gleich sein sollten
return 0;
}
// VERWUNDBAR: Koordinatenberechnung für Sicherheitsgrenze
int vulnerable_point_in_boundary(float x, float y, float boundary) {
// VERWUNDBAR: Präzisionsfehler an Grenzrändern
float distance = sqrt(x*x + y*y);
if (distance < boundary) {
return 1; // Innerhalb
}
// Punkte sehr nahe an der Grenze können falsch klassifiziert werden
return 0;
}
Sichere Lösung
// SICHER: Verwendung präziser rationaler Arithmetik
use num_rational::BigRational;
use num_bigint::BigInt;
// SICHER: Mullers Rekurrenz mit beliebiger Präzision
fn safe_recurrence(y: BigRational, z: BigRational) -> BigRational {
// SICHER: BigRational bietet exakte Arithmetik
let c108 = BigRational::from_integer(BigInt::from(108));
let c815 = BigRational::from_integer(BigInt::from(815));
let c1500 = BigRational::from_integer(BigInt::from(1500));
c108 - ((c815 - c1500 / z) / y)
}
fn safe_muller_sequence() {
let mut y = BigRational::new(BigInt::from(4), BigInt::from(1));
let mut z = BigRational::new(BigInt::from(17), BigInt::from(4)); // 4.25
// SICHER: Konvergiert korrekt gegen 5.0
for i in 0..30 {
let next = safe_recurrence(y.clone(), z.clone());
println!("Iteration {}: {}", i, next);
z = y;
y = next;
// Konvergiert korrekt gegen 5
}
}
# SICHER: Python mit präziser Dezimal-/Bruchbehandlung
from decimal import Decimal, ROUND_HALF_UP, getcontext
from fractions import Fraction
# SICHER: Präzision für Finanzberechnungen setzen
getcontext().prec = 28
# SICHER: Finanzberechnung mit Decimal
def safe_calculate_total(prices):
# SICHER: Decimal für exakte Dezimalarithmetik verwenden
total = Decimal('0')
for price in prices:
total += Decimal(str(price))
return total
# SICHER: Währungsumrechnung mit kontrollierter Rundung
def safe_convert_currency(amount, rate, decimal_places=2):
# SICHER: Explizite Präzision und Rundung
amount_dec = Decimal(str(amount))
rate_dec = Decimal(str(rate))
result = amount_dec * rate_dec
# Auf angegebene Dezimalstellen runden
return result.quantize(Decimal(10) ** -decimal_places, rounding=ROUND_HALF_UP)
# SICHER: Zinsberechnung mit Decimal
def safe_compound_interest(principal, rate, years, compounds_per_year):
# SICHER: Decimal-Arithmetik für finanzielle Präzision
p = Decimal(str(principal))
r = Decimal(str(rate))
n = Decimal(str(compounds_per_year))
t = Decimal(str(years))
result = p * (1 + r / n) ** (n * t)
return result.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
# SICHER: Exakte Division mit Fraction
def safe_split_bill(total, num_people):
# SICHER: Fraction für exakte Division verwenden
total_frac = Fraction(total).limit_denominator(100)
per_person = total_frac / num_people
# Für Anzeige in Cent umrechnen
cents = int(per_person * 100)
return cents / 100
# SICHER: Vergleich mit Toleranz
EPSILON = Decimal('0.0001')
def safe_balance_check(balance, withdrawal):
# SICHER: Mit Toleranz vergleichen
remaining = Decimal(str(balance)) - Decimal(str(withdrawal))
if abs(remaining) < EPSILON:
return "Konto leer"
elif remaining < 0:
return "Unzureichendes Guthaben"
else:
return "OK"
# SICHER: Präzisionsanforderungen validieren
def safe_calculation_with_validation(a, b, required_precision):
"""Berechnung mit Präzisionsvalidierung durchführen."""
# SICHER: Angemessene Präzision setzen
getcontext().prec = required_precision + 10 # Zusätzlicher Spielraum
a_dec = Decimal(str(a))
b_dec = Decimal(str(b))
result = a_dec * b_dec
# SICHER: Prüfen ob Präzision erhalten bleibt
if len(str(result).replace('.', '').lstrip('0')) > required_precision:
# Auf erforderliche Präzision runden
result = result.quantize(Decimal(10) ** -(required_precision - 1))
return result
// SICHER: C mit präziser Arithmetik
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
// SICHER: Ganzzahlige Cent statt Float-Dollar verwenden
typedef int64_t cents_t;
// SICHER: Puffergrößenberechnung mit Ganzzahlarithmetik
void safe_buffer_allocation(size_t data_size, int factor_percent) {
// SICHER: Ganzzahligen Prozentsatz verwenden (110% = 110)
size_t buffer_size = (data_size * factor_percent + 99) / 100;
// +99 stellt Aufrundung sicher
char* buffer = malloc(buffer_size);
// Puffergröße ist exakt
}
// SICHER: Schleife mit Ganzzahl-Zähler
void safe_integer_loop(int iterations) {
// SICHER: Ganzzahl-Zähler verwenden
for (int i = 0; i < iterations; i++) {
// Operationen durchführen
float progress = (float)i / iterations; // Nur für Anzeige
printf("Fortschritt: %.1f%%\n", progress * 100);
}
}
// SICHER: Gleitkomma-Vergleich mit Epsilon
#define EPSILON 1e-9
int safe_float_equal(double a, double b) {
// SICHER: Mit Toleranz vergleichen
return fabs(a - b) < EPSILON;
}
int safe_float_less_than(double a, double b) {
// SICHER: Präzision berücksichtigen
return (a - b) < -EPSILON;
}
// SICHER: Sicherheitsprüfung mit Toleranz
int safe_access_check(double user_level, double required_level) {
// SICHER: Epsilon-Vergleich verwenden
if (fabs(user_level - required_level) < EPSILON) {
return 1; // Zugang gewähren
}
if (user_level > required_level + EPSILON) {
return 1; // Auch gewähren wenn darüber
}
return 0;
}
// SICHER: Grenzprüfung mit Sicherheitsabstand
int safe_point_in_boundary(double x, double y, double boundary) {
// SICHER: Epsilon für Grenzunsicherheit einbeziehen
double distance = sqrt(x*x + y*y);
// Punkte innerhalb Epsilon der Grenze werden als unsicher behandelt
if (distance < boundary - EPSILON) {
return 1; // Definitiv innerhalb
} else if (distance > boundary + EPSILON) {
return 0; // Definitiv außerhalb
} else {
return -1; // An der Grenze - speziell behandeln
}
}
// SICHER: Festkomma-Arithmetik für Finanzen
typedef struct {
int64_t value; // Wert in kleinster Einheit (Cent)
int decimals; // Anzahl der Dezimalstellen
} fixed_point_t;
fixed_point_t fp_multiply(fixed_point_t a, fixed_point_t b) {
// SICHER: Exakte Multiplikation mit bekannter Präzision
fixed_point_t result;
result.value = (a.value * b.value) / pow(10, b.decimals);
result.decimals = a.decimals;
return result;
}
CVE-Beispiele
- CVE-1991-0001: Patriot-Raketensystem-Taktdrift durch Gleitkomma-Akkumulation, die Verfolgungsversagen verursachte (28 Opfer in Dhahran).
- CVE-1996-0001: Ariane-5-Raketenexplosion durch Überlauf bei Gleitkomma-zu-Ganzzahl-Konvertierung.
Verwandte CWEs
- CWE-682: Incorrect Calculation (übergeordnet)
- CWE-190: Integer Overflow or Wraparound (verwandt)
- CWE-119: Improper Restriction of Operations within Memory Buffer Bounds (kann folgen)
- CWE-834: Excessive Iteration (kann folgen)
- CWE-189: Numeric Errors (Kategorie)
Referenzen
- MITRE Corporation. "CWE-1339: Insufficient Precision or Accuracy of a Real Number." https://cwe.mitre.org/data/definitions/1339.html
- Goldberg, David. "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
- IEEE 754. "Standard for Floating-Point Arithmetic"