prevent unauthorized access to administrative db0 when connection to redis-cli

This commit is contained in:
Maxime Van Hees
2025-10-07 10:52:30 +02:00
parent 2139deb85d
commit a8720c06db
5 changed files with 525 additions and 5 deletions

View File

@@ -21,6 +21,8 @@ use ureq::{Agent, AgentBuilder};
use std::time::Duration;
use std::io::Read;
const NO_DB_SELECTED: u64 = u64::MAX;
#[derive(Clone)]
pub struct Server {
pub db_cache: std::sync::Arc<std::sync::RwLock<HashMap<u64, Arc<dyn StorageBackend>>>>,
@@ -65,7 +67,7 @@ impl Server {
db_cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
option,
client_name: None,
selected_db: 0,
selected_db: NO_DB_SELECTED,
queued_cmd: None,
current_permissions: None,
@@ -103,6 +105,17 @@ impl Server {
}
pub fn current_storage(&self) -> Result<Arc<dyn StorageBackend>, DBError> {
// Require explicit SELECT before any storage access
if self.selected_db == NO_DB_SELECTED {
return Err(DBError("No database selected. Use SELECT <id> [KEY <key>] first".to_string()));
}
// Admin DB 0 access must be authenticated with SELECT 0 KEY <admin_secret>
if self.selected_db == 0 {
if !matches!(self.current_permissions, Some(crate::rpc::Permissions::ReadWrite)) {
return Err(DBError("Admin DB 0 requires SELECT 0 KEY <admin_secret>".to_string()));
}
}
let mut cache = self.db_cache.write().unwrap();
if let Some(storage) = cache.get(&self.selected_db) {
@@ -328,6 +341,10 @@ impl Server {
/// Check if current permissions allow read operations
pub fn has_read_permission(&self) -> bool {
// No DB selected -> no permissions
if self.selected_db == NO_DB_SELECTED {
return false;
}
// If an explicit permission is set for this connection, honor it.
if let Some(perms) = self.current_permissions.as_ref() {
return matches!(*perms, crate::rpc::Permissions::Read | crate::rpc::Permissions::ReadWrite);
@@ -347,6 +364,10 @@ impl Server {
/// Check if current permissions allow write operations
pub fn has_write_permission(&self) -> bool {
// No DB selected -> no permissions
if self.selected_db == NO_DB_SELECTED {
return false;
}
// If an explicit permission is set for this connection, honor it.
if let Some(perms) = self.current_permissions.as_ref() {
return matches!(*perms, crate::rpc::Permissions::ReadWrite);