diff --git a/tinyfilemanager.php b/tinyfilemanager.php index fc1f50a..bd31855 100644 --- a/tinyfilemanager.php +++ b/tinyfilemanager.php @@ -130,7 +130,7 @@ $allowed_upload_extensions = ''; // Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. // full path, e.g http://example.com/favicon.png // local path, e.g images/icons/favicon.png -$favicon_path = ''; +$favicon_path = '';//favicon.ico // Files and folders to excluded from listing // e.g. array('myfile.html', 'personal-folder', '*.php', '/path/to/folder', ...) @@ -178,6 +178,11 @@ $ip_blacklist = array( '::' // non-routable meta ipv6 ); +// **新增:是否信任反向代理的 IP 头 (例如 Cloudflare 或 Nginx)** +// false (默认/最安全):只使用 REMOTE_ADDR,防止 IP 伪造。 +// true (使用代理时):允许读取 HTTP_X_FORWARDED_FOR 等头,获取真实客户端 IP。 +$trust_proxy = false; + // if User has the external config file, try to use it to override the default config above [config.php] // sample config - https://tinyfilemanager.github.io/config-sample.txt $config_file = __DIR__ . '/config.php'; @@ -321,20 +326,59 @@ if (isset($_GET['logout'])) { // Validate connection IP if ($ip_ruleset != 'OFF') { - function getClientIP() - { - if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { - return $_SERVER["HTTP_CF_CONNECTING_IP"]; - } else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { - return $_SERVER["HTTP_X_FORWARDED_FOR"]; - } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { - return $_SERVER['REMOTE_ADDR']; - } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { - return $_SERVER['HTTP_CLIENT_IP']; +/** + * 获取客户端 IP 地址。 + * 修复:仅在信任反向代理时才读取 X-Forwarded-For 等 HTTP 头。 + * + * @return string 客户端 IP 地址 + */ +function getClientIP() { + // 【核心改动】使用 global 关键字引入配置变量 + global $trust_proxy; + + // 如果 $trust_proxy 变量未定义,默认为 false + $trust_proxy = isset($trust_proxy) ? (bool)$trust_proxy : false; + + // 如果未启用信任代理,则直接返回 REMOTE_ADDR + if (!$trust_proxy) { + if (array_key_exists('REMOTE_ADDR', $_SERVER)) { + return $_SERVER['REMOTE_ADDR']; } return ''; } + // --- 仅在信任代理时检查 HTTP 头 --- + + // 检查 Cloudflare 代理 IP + if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { + return $_SERVER['HTTP_CF_CONNECTING_IP']; + } + + // 检查其他常见的反向代理头 (X-Forwarded-For) + if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { + // 取第一个 IP (最左边的,通常是客户端真实 IP) + $ip = trim(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]); + if (filter_var($ip, FILTER_VALIDATE_IP)) { + return $ip; + } + } + + // 检查 HTTP_CLIENT_IP + if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { + return $_SERVER['HTTP_CLIENT_IP']; + } + + // 默认返回 REMOTE_ADDR + if (array_key_exists('REMOTE_ADDR', $_SERVER)) { + return $_SERVER['REMOTE_ADDR']; + } + + return ''; +} + + + + $clientIp = getClientIP(); $proceed = false; $whitelisted = in_array($clientIp, $ip_whitelist); @@ -501,14 +545,38 @@ defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); /*************************** ACTIONS ***************************/ - function sanitizePath($path) { +/** + * 清理和验证路径,强制路径在 FM_ROOT_PATH 内部。 + * + * @param string $path 待检查的路径 + * @return string|false 成功返回绝对路径,失败则终止程序。 + */ +function sanitizePath($path) { + // 1. 初始检查,确保路径以 '/' 开头 if (substr($path, 0, 1) !== '/') { die('Invalid file path.'); } - if ($path === '/') { - return '/'; + + // 2. 获取路径的真实绝对路径 + $realPath = realpath($path); + + // 3. 获取文件管理器根目录的真实绝对路径 (需要先定义 FM_ROOT_PATH) + // 假设 FM_ROOT_PATH 是在文件顶部定义的常量。 + $rootDir = realpath(FM_ROOT_PATH); + + // --- 核心安全检查 --- + // 4. 检查 $realPath 是否在 $rootDir 内部 + if ($realPath === false || strpos($realPath, $rootDir) !== 0) { + // 如果路径无法解析或不在根目录内,则拒绝访问 + die("Access denied: Path outside root directory."); } - return realpath($path); + // ---------------------- + + // 5. 如果路径在根目录内,则返回规范化后的路径 + if ($realPath === $rootDir) { + return $rootDir; + } + return $realPath; } // 忽略用户断开连接,确保脚本完成输出 @@ -716,19 +784,42 @@ function getFileList($dir) return $files; } // create file lists HTML +/** + * 生成目录列表的 HTML 页面 + * 修复:对目录名和文件名进行 htmlspecialchars 转义,防止 XSS 攻击。 + * + * @param string $dir 当前目录 + * @param array $fileList 文件/目录列表 + * @return string 生成的 HTML + */ function generateDirectoryListing($dir, $fileList) { - $html = "Index of {$dir}"; - $html .= "

Index of {$dir}