feat(security): release v0.7.0 with comprehensive security hardening (S-01 to S-11)
Sanctum Release / Build & Release (Windows x86_64) (push) Waiting to run
Sanctum Release / Build & Release (Windows x86_64) (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
use std::path::PathBuf;
|
||||
use sanctum::crypto::{
|
||||
derive_kek, generate_dek, generate_salt, wrap_dek, KdfParams, MIN_MEMORY_COST_KIB,
|
||||
MIN_TIME_COST,
|
||||
};
|
||||
use sanctum::mount::is_loopback_host;
|
||||
use sanctum::storage::Database;
|
||||
|
||||
#[test]
|
||||
fn test_is_loopback_host_comprehensive() {
|
||||
// Gültige IPv4 Loopback Varianten
|
||||
assert!(is_loopback_host("127.0.0.1"));
|
||||
assert!(is_loopback_host("127.0.0.1:80"));
|
||||
assert!(is_loopback_host("127.0.0.1:8080"));
|
||||
assert!(is_loopback_host("127.0.0.1:65535"));
|
||||
|
||||
// Gültige Hostname Loopback Varianten
|
||||
assert!(is_loopback_host("localhost"));
|
||||
assert!(is_loopback_host("localhost:80"));
|
||||
assert!(is_loopback_host("localhost:8443"));
|
||||
assert!(is_loopback_host("LOCALHOST"));
|
||||
assert!(is_loopback_host("LocalHost:9000"));
|
||||
|
||||
// Gültige IPv6 Loopback Varianten
|
||||
assert!(is_loopback_host("[::1]"));
|
||||
assert!(is_loopback_host("[::1]:80"));
|
||||
assert!(is_loopback_host("[::1]:8443"));
|
||||
assert!(is_loopback_host("::1"));
|
||||
|
||||
// DNS-Rebinding & Spoofing Angriffe (MÜSSEN abgewiesen werden)
|
||||
assert!(!is_loopback_host("127.0.0.1.attacker.com"));
|
||||
assert!(!is_loopback_host("localhost.attacker.com"));
|
||||
assert!(!is_loopback_host("localhost.evil.org:8080"));
|
||||
assert!(!is_loopback_host("notlocalhost"));
|
||||
assert!(!is_loopback_host("attacker.com"));
|
||||
assert!(!is_loopback_host("attacker.com:127001"));
|
||||
assert!(!is_loopback_host("192.168.1.1"));
|
||||
assert!(!is_loopback_host("10.0.0.1"));
|
||||
assert!(!is_loopback_host("0.0.0.0"));
|
||||
assert!(!is_loopback_host(""));
|
||||
assert!(!is_loopback_host(" "));
|
||||
assert!(!is_loopback_host("foo:bar:baz"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wal_and_shm_cleanup_on_close() {
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let container_path: PathBuf = temp_dir.join(format!("test_wal_cleanup_{}.sanctum", std::process::id()));
|
||||
if container_path.exists() {
|
||||
let _ = std::fs::remove_file(&container_path);
|
||||
}
|
||||
|
||||
let salt = generate_salt();
|
||||
let kdf_params = KdfParams {
|
||||
memory_cost: MIN_MEMORY_COST_KIB,
|
||||
time_cost: MIN_TIME_COST,
|
||||
parallelism: 1,
|
||||
};
|
||||
let kek = derive_kek("WalCleanupPassword2026!", &salt, &kdf_params).unwrap();
|
||||
let dek = generate_dek();
|
||||
let (wrapped_dek, nonce, tag) = wrap_dek(&kek, &dek).unwrap();
|
||||
|
||||
let db = Database::open(&container_path).unwrap();
|
||||
db.init_schema(&salt, &kdf_params, &wrapped_dek, &nonce, &tag).unwrap();
|
||||
|
||||
// Erstelle Knoten, um Schreibaktivität im WAL zu erzeugen
|
||||
let _ = db.create_node(1, "test_file.txt", false).unwrap();
|
||||
db.checkpoint().unwrap();
|
||||
drop(db);
|
||||
|
||||
// Bereinigungslogik (wie in mount.rs unmount) ausführen
|
||||
let base_os = container_path.as_os_str().to_os_string();
|
||||
let mut wal = base_os.clone();
|
||||
wal.push("-wal");
|
||||
let _ = std::fs::remove_file(&wal);
|
||||
let mut shm = base_os;
|
||||
shm.push("-shm");
|
||||
let _ = std::fs::remove_file(&shm);
|
||||
|
||||
assert!(!PathBuf::from(wal).exists(), "WAL-Datei darf nach sauberem Unmount nicht zurückbleiben");
|
||||
assert!(!PathBuf::from(shm).exists(), "SHM-Datei darf nach sauberem Unmount nicht zurückbleiben");
|
||||
|
||||
let _ = std::fs::remove_file(&container_path);
|
||||
}
|
||||
Reference in New Issue
Block a user