""" SSH 唯讀診斷指令白名單 — 防止 RCE 2026-05-04 ogt + Claude Sonnet 4.6: 設計原則: - 只允許純唯讀指令(top/uptime/free/df/ps/cat /proc/*) - 禁止任何 shell metachar(compound/pipeline/substitution/redirect) - 由 validate_kubectl_command() 的 "ssh " 豁免確保進規則路徑; 本模組為補充安全層,供未來 _ssh_execute() 執行前再次驗證。 """ # 允許的指令前綴(唯讀診斷用) _SAFE_PREFIXES: tuple[str, ...] = ( "top -bn1", "uptime", "free -m", "free -h", "df -h", "df -hT", "iostat", "vmstat", "ps aux", "ps -ef", "cat /proc/loadavg", "cat /proc/meminfo", "cat /proc/cpuinfo", "echo ", ) # 禁止的 shell metachar — 防止指令注入 _DANGEROUS_PATTERNS: tuple[str, ...] = ( ";", "&&", "||", "|", ">", "<", "`", "$(", "${", "\\n", "\n", "rm ", "kill ", "pkill ", "reboot", "shutdown", "poweroff", "dd ", "mkfs", "fdisk", "wget ", "curl ", "nc ", "ncat ", "bash ", "sh ", "python", "perl", "ruby", "exec ", ) def is_safe_ssh_command(cmd: str) -> bool: """ 驗證 SSH 指令是否為唯讀安全指令。 規則: 1. 必須以 _SAFE_PREFIXES 其中一個前綴開頭 2. 不得含有任何 _DANGEROUS_PATTERNS Args: cmd: 要驗證的 SSH 指令字串(不含前導 "ssh '" 包裝) Returns: True — 安全,可執行 False — 含危險模式,應拒絕 """ if not cmd or not cmd.strip(): return False cmd_stripped = cmd.strip() # 先阻擋危險模式(優先於前綴白名單) for pattern in _DANGEROUS_PATTERNS: if pattern in cmd_stripped: return False # 必須以白名單前綴開頭 return any(cmd_stripped.startswith(prefix) for prefix in _SAFE_PREFIXES) def extract_inner_command(ssh_cmd: str) -> str: """ 從完整 SSH 指令中提取內層指令供 is_safe_ssh_command() 驗證。 範例: "ssh 192.168.1.1 'uptime'" → "uptime" "ssh -o StrictHostKeyChecking=accept-new host 'free -m'" → "free -m" Args: ssh_cmd: 完整 SSH 指令字串 Returns: 內層指令字串;若解析失敗返回原始字串 """ if not ssh_cmd.startswith("ssh "): return ssh_cmd # 找最後一對單引號或雙引號包裝的指令 for quote in ("'", '"'): last_open = ssh_cmd.rfind(quote) if last_open == -1: continue first_open = ssh_cmd.find(quote) if first_open == last_open: continue return ssh_cmd[first_open + 1 : last_open] return ssh_cmd