You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下C语言开发的客户端-服务器如何防范路径遍历文件访问?

防止路径遍历攻击的解决方案

这是个典型的路径遍历安全漏洞,必须在服务器端对客户端传入的文件名做严格校验,绝对不能直接信任用户输入。下面给你几个实用的解决思路,从简单到进阶都有:

1. 直接过滤危险路径组件

最基础的做法是检查传入的文件名是否包含../、./或者绝对路径(以/开头),如果有直接拒绝请求。这种方法实现简单,能挡住大部分常见的攻击:

#include <string.h>
#include <stdbool.h>

bool is_filename_safe(const char *filename) {
    // 拒绝绝对路径
    if (filename[0] == '/') {
        return false;
    }
    // 拒绝包含上级目录或当前目录的路径
    if (strstr(filename, "../") != NULL || strstr(filename, "./") != NULL) {
        return false;
    }
    // 额外:拒绝包含路径分隔符的(如果只允许访问当前目录的文件)
    if (strchr(filename, '/') != NULL) {
        return false;
    }
    return true;
}

2. 解析真实路径并校验目录范围

更可靠的方法是把用户输入的文件名拼接成完整路径后,用realpath()解析出它的真实绝对路径,然后检查这个路径是否落在你允许的服务器工作目录之内。这种方法能绕过一些过滤技巧(比如符号链接、特殊编码路径等):

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>

bool is_path_within_allowed_dir(const char *filename, const char *allowed_dir) {
    char allowed_abs_path[PATH_MAX];
    char requested_abs_path[PATH_MAX];
    
    // 先获取允许目录的绝对路径
    if (realpath(allowed_dir, allowed_abs_path) == NULL) {
        perror("Failed to resolve allowed directory");
        return false;
    }
    
    // 拼接用户输入到允许目录下
    snprintf(requested_abs_path, sizeof(requested_abs_path), "%s/%s", allowed_abs_path, filename);
    
    // 解析请求路径的真实路径(自动处理../、符号链接等)
    if (realpath(requested_abs_path, requested_abs_path) == NULL) {
        // 文件不存在或路径无效,直接拒绝
        return false;
    }
    
    // 检查真实路径是否以允许目录的绝对路径开头,同时避免前缀误匹配
    size_t allowed_len = strlen(allowed_abs_path);
    if (strncmp(requested_abs_path, allowed_abs_path, allowed_len) != 0 || 
        (requested_abs_path[allowed_len] != '\0' && requested_abs_path[allowed_len] != '/')) {
        return false;
    }
    
    return true;
}

3. 切换工作目录后仅操作文件名

可以让服务器进程先切换到指定的工作目录(比如chdir("/home/server/files")),然后只使用文件名的basename部分来操作文件。这样即使用户传入../try.txt,在当前目录下尝试访问上级目录也会失败(前提是限制服务器进程的上级目录权限):

#include <unistd.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>

// 初始化时切换到工作目录
bool setup_working_dir(const char *work_dir) {
    if (chdir(work_dir) == -1) {
        perror("Failed to change to working directory");
        return false;
    }
    return true;
}

// 处理客户端请求时,提取安全的纯文件名
char *get_safe_filename(const char *input_filename) {
    // basename会修改原字符串,所以先复制一份
    char *filename_copy = strdup(input_filename);
    if (filename_copy == NULL) {
        return NULL;
    }
    char *safe_name = basename(filename_copy);
    // 额外校验,防止极端情况
    if (strstr(safe_name, "../") != NULL) {
        free(filename_copy);
        return NULL;
    }
    // 返回的safe_name指向filename_copy内部,不要单独释放safe_name
    return filename_copy;
}

4. 使用沙箱限制进程(进阶)

如果对安全性要求极高,可以用chroot把服务器进程限制在指定的目录“监狱”里。这样即使存在路径遍历漏洞,进程也无法访问监狱外的任何文件。不过这种方法需要root权限来设置,并且要正确配置环境(比如复制必要的库文件、设备文件到chroot目录),适合生产环境的高安全场景。

关键注意事项

  • 永远不要信任客户端的任何输入,所有传入的文件名都必须经过校验
  • 最好组合使用多种方法(比如先过滤危险字符,再校验真实路径),提升安全性
  • 限制服务器进程的权限:用非root用户运行服务器,并且只给它工作目录的读写权限,即使被攻击也能降低损失

内容的提问来源于stack exchange,提问作者Ennio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:10:39