Verwendung hartcodierter, sicherheitsrelevanter Konstanten
Beschreibung
Verwendung hartcodierter, sicherheitsrelevanter Konstanten ist eine Schwachstelle, bei der ein Produkt hartcodierte Konstanten anstelle von konfigurierbaren Werten für sicherheitskritische Parameter verwendet. Dies umfasst hartcodierte kryptografische Schlüssel, Salts, Initialisierungsvektoren, Algorithmus-Identifikatoren, Iterationszähler, Schlüsselgrößen, Timeout-Werte und andere sicherheitsrelevante Parameter. Wenn diese Werte direkt im Code eingebettet sind, werden sie schwer zu ändern, können durch Reverse-Engineering offengelegt werden und erzeugen Konsistenzprobleme zwischen Deployments, wo unterschiedliche Sicherheitskonfigurationen benötigt werden könnten.
Risiko
Hartcodierte Sicherheitskonstanten erzeugen erhebliche Schwachstellen. Im Code eingebettete kryptografische Schlüssel können durch Reverse-Engineering, Dekompilierung oder Quellcode-Lecks extrahiert werden und kompromittieren alle Systeme, die diesen Schlüssel verwenden. Hartcodierte Salts eliminieren den Einzigartigkeitsvorteil, den Salts bieten, und machen Rainbow-Table-Angriffe machbar. Feste Iterationszähler können mit zunehmender Rechenleistung unzureichend werden, können aber ohne Codeänderungen nicht aktualisiert werden. Hartcodierte Timeouts können für verschiedene Deployment-Umgebungen unangemessen lang oder kurz sein. Wenn Sicherheitskonstanten entdeckt werden, erfordert ihre Änderung Code-Updates, Tests und Deployment anstelle einfacher Konfigurationsänderungen, was zu verzögerten Reaktionen auf Sicherheitsvorfälle führt.
Lösung
Externalisieren Sie alle sicherheitsrelevanten Konstanten in Konfigurationsdateien, Umgebungsvariablen oder sichere Parameterspeicher. Verwenden Sie Schlüsselverwaltungssysteme für kryptografische Schlüssel. Generieren Sie einzigartige Salts pro Operation anstelle fester Werte. Machen Sie Iterationszähler und Schlüsselgrößen konfigurierbar mit sicheren Standardwerten. Speichern Sie Sicherheits-Timeouts in Konfiguration, die pro Umgebung angepasst werden kann. Wenn Konstanten im Code sein müssen, verwenden Sie benannte Konstanten mit klarer Dokumentation anstelle magischer Zahlen. Implementieren Sie Konfigurationsvalidierung, um sicherzustellen, dass Sicherheitsparameter Mindestanforderungen erfüllen. Verwenden Sie verschiedene Sicherheitskonfigurationen für Entwicklungs-, Test- und Produktionsumgebungen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Hartcodierte kryptografische Schlüssel oder andere Geheimnisse können aus dem Code extrahiert werden, was Angreifern ermöglicht, sensible Daten zu entschlüsseln oder Authentifizierung zu umgehen. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Hartcodierte Sicherheitsparameter wie Timeouts oder Wiederholungslimits können unzureichend sein, was Brute-Force-Angriffe oder Session-Fixation ermöglicht. |
| Sonstige | Bereich: Sonstige Wartbarkeit reduzieren - Hartcodierte Konstanten erschweren das Aktualisieren von Sicherheitsparametern als Reaktion auf neue Bedrohungen oder sich ändernde Anforderungen ohne Codeänderungen. |
Beispielcode + Lösungscode
Verwundbarer Code
// Verwundbar: Hartcodierte sicherheitsrelevante Konstanten
public class VerwundbareCrypto {
// Verwundbar: Hartcodierter Verschlüsselungsschlüssel
private static final byte[] SECRET_KEY =
"MySecretKey12345".getBytes(StandardCharsets.UTF_8);
// Verwundbar: Hartcodierter IV (sollte pro Verschlüsselung zufällig sein)
private static final byte[] INIT_VECTOR =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
// Verwundbar: Hartcodiertes Salt (hebt Zweck des Saltens auf)
private static final String PASSWORD_SALT = "FixedSalt123";
// Verwundbar: Hartcodierter Iterationszähler (kann unsicher werden)
private static final int PBKDF2_ITERATIONS = 1000; // Zu niedrig!
// Verwundbar: Hartcodierte Schlüsselgröße
private static final int KEY_SIZE = 128; // Sollte 256 sein
public byte[] encrypt(String plaintext) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(INIT_VECTOR);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(plaintext.getBytes());
}
public String hashPassword(String password) {
// Verwundbar: Gleiches Salt für alle Passwörter
String salted = PASSWORD_SALT + password;
return DigestUtils.sha256Hex(salted);
}
}
// Verwundbar: Hartcodierte Sicherheits-Timeouts
public class VerwundbareSession {
// Verwundbar: Hartcodierte Timeout-Werte
private static final int SESSION_TIMEOUT = 3600; // 1 Stunde
private static final int TOKEN_EXPIRY = 86400; // 24 Stunden
private static final int MAX_LOGIN_ATTEMPTS = 3;
private static final int LOCKOUT_DURATION = 300; // 5 Minuten
// Diese können für verschiedene Umgebungen zu lang oder zu kurz sein
}
# Verwundbar: Hartcodierte Sicherheitskonstanten in Python
import hashlib
from Crypto.Cipher import AES
class VerwundbareSecurity:
# Verwundbar: Hartcodierter API-Schlüssel
API_SECRET_KEY = "sk_live_hardcoded_key_12345"
# Verwundbar: Hartcodierter Verschlüsselungsschlüssel
ENCRYPTION_KEY = b"0123456789ABCDEF" # 16 Bytes für AES-128
# Verwundbar: Hartcodiertes JWT-Geheimnis
JWT_SECRET = "super_secret_jwt_key"
# Verwundbar: Hartcodierter HMAC-Schlüssel
HMAC_KEY = b"hmac_secret_key_value"
# Verwundbar: Hartcodierter Passwort-Pepper
PASSWORD_PEPPER = "application_pepper_2023"
def encrypt_data(self, data):
# Verwundbar: Verwendung hartcodiertem Schlüssel und kein IV
cipher = AES.new(self.ENCRYPTION_KEY, AES.MODE_ECB) # ECB ist auch schlecht
return cipher.encrypt(self._pad(data))
def hash_password(self, password):
# Verwundbar: Hartcodierter Pepper, kein einzigartiges Salt
peppered = password + self.PASSWORD_PEPPER
return hashlib.sha256(peppered.encode()).hexdigest()
def generate_token(self, user_id):
# Verwundbar: Hartcodiertes JWT-Geheimnis
import jwt
return jwt.encode(
{"user_id": user_id},
self.JWT_SECRET,
algorithm="HS256"
)
# Verwundbar: Hartcodierte Sicherheitslimits
MAX_FILE_SIZE = 10485760 # 10MB - könnte Anpassung brauchen
MAX_REQUEST_SIZE = 1048576 # 1MB - festes Limit
RATE_LIMIT = 100 # Anfragen pro Minute
BCRYPT_ROUNDS = 10 # Sollte konfigurierbar und höher sein
// Verwundbar: Hartcodierte Konstanten in Node.js
const crypto = require('crypto');
// Verwundbar: Hartcodierter Verschlüsselungsschlüssel
const ENCRYPTION_KEY = 'abcdefghijklmnop'; // 16 Bytes
// Verwundbar: Hartcodiertes HMAC-Geheimnis
const HMAC_SECRET = 'hmac_secret_123';
// Verwundbar: Hartcodiertes JWT-Geheimnis
const JWT_SECRET = 'my_jwt_secret_key';
// Verwundbar: Hartcodierte Session-Einstellungen
const SESSION_CONFIG = {
secret: 'session_secret_value', // Hartcodiert
maxAge: 3600000, // Feste 1 Stunde
secure: false, // Sollte von Umgebung abhängen
sameSite: 'lax' // Feste Richtlinie
};
// Verwundbar: Hartcodierte Krypto-Parameter
const CRYPTO_CONFIG = {
algorithm: 'aes-128-cbc', // Sollte konfigurierbar sein
iterations: 10000, // Feste PBKDF2-Iterationen
keyLength: 16, // Feste Schlüssellänge
saltLength: 16 // Feste Salt-Länge
};
function encryptData(data) {
// Verwundbar: Verwendung hartcodiertem Schlüssel
const cipher = crypto.createCipheriv(
'aes-128-cbc',
ENCRYPTION_KEY,
Buffer.alloc(16) // Null-IV - noch schlimmer!
);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
}
function signData(data) {
// Verwundbar: Hartcodierter HMAC-Schlüssel
return crypto.createHmac('sha256', HMAC_SECRET)
.update(data)
.digest('hex');
}
<?php
// Verwundbar: Hartcodierte Sicherheitskonstanten in PHP
class VerwundbareCrypto {
// Verwundbar: Hartcodierter Verschlüsselungsschlüssel
private const ENCRYPTION_KEY = 'MySuperSecretKey';
// Verwundbar: Hartcodierter IV
private const IV = '1234567890123456';
// Verwundbar: Hartcodierter HMAC-Schlüssel
private const HMAC_KEY = 'hmac_key_fixed';
// Verwundbar: Hartcodierter bcrypt-Kostenfaktor (zu niedrig)
private const BCRYPT_COST = 4; // Sollte mindestens 12 sein
// Verwundbar: Hartcodierte Passwortanforderungen
private const MIN_PASSWORD_LENGTH = 6; // Zu kurz
private const REQUIRE_SPECIAL_CHAR = false; // Sollte true sein
public function encrypt($data) {
// Verwundbar: Verwendung hartcodiertem Schlüssel und IV
return openssl_encrypt(
$data,
'AES-128-CBC',
self::ENCRYPTION_KEY,
0,
self::IV
);
}
public function hashPassword($password) {
// Verwundbar: Fester niedriger Kostenfaktor
return password_hash($password, PASSWORD_BCRYPT, [
'cost' => self::BCRYPT_COST
]);
}
public function signData($data) {
// Verwundbar: Hartcodierter HMAC-Schlüssel
return hash_hmac('sha256', $data, self::HMAC_KEY);
}
}
// Verwundbar: Hartcodierte Sicherheits-Timeouts
define('SESSION_TIMEOUT', 3600);
define('CSRF_TOKEN_EXPIRY', 1800);
define('PASSWORD_RESET_EXPIRY', 86400);
define('MAX_LOGIN_ATTEMPTS', 5);
?>
Lösungscode
// Behoben: Konfigurierbare Sicherheitskonstanten
public class SichereCrypto {
private final SecureRandom secureRandom;
private final SecurityConfig config;
private final KeyManagementService keyService;
public SichereCrypto(SecurityConfig config, KeyManagementService keyService) {
this.config = config;
this.keyService = keyService;
this.secureRandom = new SecureRandom();
}
public EncryptedData encrypt(String plaintext) throws Exception {
// Behoben: Schlüssel von Schlüsselverwaltungsdienst abrufen
byte[] key = keyService.getEncryptionKey();
// Behoben: Zufälligen IV für jede Verschlüsselung generieren
byte[] iv = new byte[config.getIvSize()];
secureRandom.nextBytes(iv);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// Behoben: Algorithmus konfigurierbar
Cipher cipher = Cipher.getInstance(config.getCipherAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// IV mit Chiffretext zurückgeben (IV muss nicht geheim sein)
return new EncryptedData(iv, ciphertext);
}
public String hashPassword(String password) {
// Behoben: Einzigartiges Salt pro Passwort generieren
byte[] salt = new byte[config.getSaltSize()];
secureRandom.nextBytes(salt);
// Behoben: Konfigurierbarer Iterationszähler aus Konfiguration
int iterations = config.getPbkdf2Iterations();
int keyLength = config.getDerivedKeyLength();
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
iterations,
keyLength
);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = factory.generateSecret(spec).getEncoded();
// Salt und Hash zusammen zurückgeben
return Base64.getEncoder().encodeToString(salt) + ":" +
Base64.getEncoder().encodeToString(hash);
}
}
// Behoben: Sicherheitskonfigurationsklasse
public class SecurityConfig {
private final int ivSize;
private final int saltSize;
private final int pbkdf2Iterations;
private final int derivedKeyLength;
private final String cipherAlgorithm;
public SecurityConfig() {
// Aus Umgebung oder Konfigurationsdatei laden
this.ivSize = getIntProperty("CRYPTO_IV_SIZE", 16);
this.saltSize = getIntProperty("CRYPTO_SALT_SIZE", 32);
this.pbkdf2Iterations = getIntProperty("PBKDF2_ITERATIONS", 310000);
this.derivedKeyLength = getIntProperty("DERIVED_KEY_LENGTH", 256);
this.cipherAlgorithm = getProperty("CIPHER_ALGORITHM", "AES/GCM/NoPadding");
// Minimale Sicherheitsanforderungen validieren
validateConfig();
}
private void validateConfig() {
if (pbkdf2Iterations < 100000) {
throw new SecurityException("PBKDF2-Iterationen zu niedrig");
}
if (derivedKeyLength < 256) {
throw new SecurityException("Schlüssellänge zu kurz");
}
}
// Getter...
}
# Behoben: Konfigurierbare Sicherheitsparameter in Python
import os
import secrets
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
class SichereSecurity:
def __init__(self, config=None):
self.config = config or SecurityConfig()
self.key_service = KeyManagementService()
def encrypt_data(self, data: bytes) -> dict:
# Behoben: Schlüssel von Schlüsselverwaltungsdienst abrufen
key = self.key_service.get_encryption_key()
# Behoben: Zufälligen IV für jede Verschlüsselung generieren
iv = secrets.token_bytes(self.config.iv_size)
# Behoben: Authentifizierte Verschlüsselung verwenden (GCM)
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(data) + encryptor.finalize()
return {
'iv': iv,
'ciphertext': ciphertext,
'tag': encryptor.tag
}
def hash_password(self, password: str) -> str:
# Behoben: Einzigartiges Salt pro Passwort generieren
salt = secrets.token_bytes(self.config.salt_size)
# Behoben: Konfigurierbare Iterationen
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=self.config.derived_key_length,
salt=salt,
iterations=self.config.pbkdf2_iterations,
backend=default_backend()
)
key = kdf.derive(password.encode())
import base64
return base64.b64encode(salt).decode() + ':' + base64.b64encode(key).decode()
def generate_token(self, user_id: str) -> str:
import jwt
# Behoben: Geheimnis von Schlüsseldienst abrufen
secret = self.key_service.get_jwt_secret()
return jwt.encode(
{"user_id": user_id},
secret,
algorithm=self.config.jwt_algorithm
)
class SecurityConfig:
"""Sicherheitskonfiguration aus Umgebung geladen."""
def __init__(self):
# Behoben: Alle Parameter aus Umgebung mit sicheren Standardwerten
self.iv_size = int(os.environ.get('CRYPTO_IV_SIZE', '12')) # 96 Bits für GCM
self.salt_size = int(os.environ.get('CRYPTO_SALT_SIZE', '32'))
self.pbkdf2_iterations = int(os.environ.get('PBKDF2_ITERATIONS', '310000'))
self.derived_key_length = int(os.environ.get('DERIVED_KEY_LENGTH', '32'))
self.jwt_algorithm = os.environ.get('JWT_ALGORITHM', 'HS256')
# Behoben: Mindestanforderungen validieren
self._validate()
def _validate(self):
if self.pbkdf2_iterations < 100000:
raise ValueError("PBKDF2-Iterationen müssen mindestens 100000 sein")
if self.salt_size < 16:
raise ValueError("Salt-Größe muss mindestens 16 Bytes sein")
// Behoben: Konfigurierbare Sicherheitskonstanten in Node.js
const crypto = require('crypto');
class SecurityConfig {
constructor() {
// Behoben: Aus Umgebung laden
this.ivSize = parseInt(process.env.CRYPTO_IV_SIZE || '12');
this.saltSize = parseInt(process.env.CRYPTO_SALT_SIZE || '32');
this.pbkdf2Iterations = parseInt(process.env.PBKDF2_ITERATIONS || '310000');
this.keyLength = parseInt(process.env.KEY_LENGTH || '32');
this.algorithm = process.env.CIPHER_ALGORITHM || 'aes-256-gcm';
// Behoben: Konfiguration validieren
this.validate();
}
validate() {
if (this.pbkdf2Iterations < 100000) {
throw new Error('PBKDF2-Iterationen zu niedrig');
}
if (this.keyLength < 32) {
throw new Error('Schlüssellänge zu kurz');
}
}
}
class SichereCrypto {
constructor(config, keyService) {
this.config = config || new SecurityConfig();
this.keyService = keyService;
}
async encrypt(data) {
// Behoben: Schlüssel von Schlüsseldienst abrufen
const key = await this.keyService.getEncryptionKey();
// Behoben: Zufälligen IV für jede Verschlüsselung generieren
const iv = crypto.randomBytes(this.config.ivSize);
// Behoben: Authentifizierte Verschlüsselung verwenden
const cipher = crypto.createCipheriv(this.config.algorithm, key, iv);
let ciphertext = cipher.update(data, 'utf8');
ciphertext = Buffer.concat([ciphertext, cipher.final()]);
const authTag = cipher.getAuthTag();
return {
iv: iv.toString('base64'),
ciphertext: ciphertext.toString('base64'),
authTag: authTag.toString('base64')
};
}
hashPassword(password) {
// Behoben: Einzigartiges Salt generieren
const salt = crypto.randomBytes(this.config.saltSize);
// Behoben: Konfigurierbare Iterationen verwenden
const hash = crypto.pbkdf2Sync(
password,
salt,
this.config.pbkdf2Iterations,
this.config.keyLength,
'sha256'
);
return salt.toString('base64') + ':' + hash.toString('base64');
}
}
// Behoben: Session-Konfiguration aus Umgebung
const sessionConfig = {
secret: process.env.SESSION_SECRET, // Erforderlich, kein Standard
maxAge: parseInt(process.env.SESSION_MAX_AGE || '3600000'),
secure: process.env.NODE_ENV === 'production',
sameSite: process.env.SESSION_SAME_SITE || 'strict'
};
if (!sessionConfig.secret) {
throw new Error('SESSION_SECRET Umgebungsvariable erforderlich');
}
module.exports = { SecurityConfig, SichereCrypto, sessionConfig };
<?php
// Behoben: Konfigurierbare Sicherheitsparameter in PHP
class SecurityConfig {
private int $ivSize;
private int $saltSize;
private int $pbkdf2Iterations;
private int $bcryptCost;
private string $cipherAlgorithm;
public function __construct() {
// Behoben: Aus Umgebung mit sicheren Standardwerten laden
$this->ivSize = (int)getenv('CRYPTO_IV_SIZE') ?: 16;
$this->saltSize = (int)getenv('CRYPTO_SALT_SIZE') ?: 32;
$this->pbkdf2Iterations = (int)getenv('PBKDF2_ITERATIONS') ?: 310000;
$this->bcryptCost = (int)getenv('BCRYPT_COST') ?: 12;
$this->cipherAlgorithm = getenv('CIPHER_ALGORITHM') ?: 'aes-256-gcm';
$this->validate();
}
private function validate(): void {
if ($this->pbkdf2Iterations < 100000) {
throw new SecurityException('PBKDF2-Iterationen zu niedrig');
}
if ($this->bcryptCost < 10) {
throw new SecurityException('Bcrypt-Kostenfaktor zu niedrig');
}
}
// Getter...
public function getIvSize(): int { return $this->ivSize; }
public function getSaltSize(): int { return $this->saltSize; }
public function getPbkdf2Iterations(): int { return $this->pbkdf2Iterations; }
public function getBcryptCost(): int { return $this->bcryptCost; }
public function getCipherAlgorithm(): string { return $this->cipherAlgorithm; }
}
class SichereCrypto {
private SecurityConfig $config;
private KeyManagementService $keyService;
public function __construct(SecurityConfig $config, KeyManagementService $keyService) {
$this->config = $config;
$this->keyService = $keyService;
}
public function encrypt(string $data): array {
// Behoben: Schlüssel von Schlüsseldienst abrufen
$key = $this->keyService->getEncryptionKey();
// Behoben: Zufälligen IV generieren
$iv = random_bytes($this->config->getIvSize());
// Behoben: Authentifizierte Verschlüsselung verwenden
$ciphertext = openssl_encrypt(
$data,
$this->config->getCipherAlgorithm(),
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
return [
'iv' => base64_encode($iv),
'ciphertext' => base64_encode($ciphertext),
'tag' => base64_encode($tag)
];
}
public function hashPassword(string $password): string {
// Behoben: Konfigurierbaren bcrypt-Kostenfaktor verwenden
return password_hash($password, PASSWORD_BCRYPT, [
'cost' => $this->config->getBcryptCost()
]);
}
}
// Behoben: Sicherheits-Timeouts aus Umgebung
class SecurityTimeouts {
public static function getSessionTimeout(): int {
return (int)getenv('SESSION_TIMEOUT') ?: 3600;
}
public static function getCsrfTokenExpiry(): int {
return (int)getenv('CSRF_TOKEN_EXPIRY') ?: 1800;
}
public static function getPasswordResetExpiry(): int {
return (int)getenv('PASSWORD_RESET_EXPIRY') ?: 3600; // 1 Stunde, nicht 24
}
public static function getMaxLoginAttempts(): int {
return (int)getenv('MAX_LOGIN_ATTEMPTS') ?: 5;
}
}
?>
CVE-Beispiele
- CVE-2022-26138: Atlassian Confluence Questions verwendete hartcodiertes Passwort für das disabledsystemuser-Konto.
- CVE-2021-29078: NetModule Router Software enthielt hartcodierte kryptografische Schlüssel.
- CVE-2020-4574: IBM Security Key Lifecycle Manager verwendete hartcodierte Anmeldedaten.
Referenzen
- MITRE Corporation. "CWE-547: Use of Hard-coded, Security-relevant Constants." https://cwe.mitre.org/data/definitions/547.html
- OWASP. "Cryptographic Storage Cheat Sheet."
- NIST. "Key Management Guidelines."